Compare commits
188 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
72b59b7972 | ||
|
179b4e456a | ||
|
bd2e22ddcc | ||
|
9f370f0bc6 | ||
|
2ed41a0fb0 | ||
|
5345006580 | ||
|
3e6632807a | ||
|
0eaa455fbe | ||
|
6b134d11ff | ||
|
c865e0dc78 | ||
|
66d81336ad | ||
|
ef2b18f1bf | ||
|
7acf2cd528 | ||
|
2b5df70d5a | ||
|
dcd1fafc85 | ||
|
84203501a5 | ||
|
34f8515d44 | ||
|
d9398f1eff | ||
|
9d5c9200e8 | ||
|
3e8bb098ff | ||
|
6c41c32949 | ||
|
62822051a9 | ||
|
4bd5988e31 | ||
|
5949a4998e | ||
|
dae53fadc4 | ||
|
b1d3b7e697 | ||
|
0bd12bdf0a | ||
|
272d503055 | ||
|
f33cc7cac2 | ||
|
864cda1bed | ||
|
1928fa6b0c | ||
|
e801ca642e | ||
|
edbf322a6f | ||
|
ea55152aac | ||
|
158f660695 | ||
|
294bd0376b | ||
|
0918776d00 | ||
|
47500c833f | ||
|
837e389b4c | ||
|
1fadea3027 | ||
|
b9332b2578 | ||
|
f6c1bfac59 | ||
|
ed34101ba3 | ||
|
21f0828424 | ||
|
191515bbc3 | ||
|
34a6e30769 | ||
|
ce6ddec02d | ||
|
cfe34614da | ||
|
55debe7570 | ||
|
a36f6e00eb | ||
|
1cdd9dfb1b | ||
|
7ed0cd6823 | ||
|
f80b5430f8 | ||
|
4a2e736594 | ||
|
27b2d584ab | ||
|
4e97099bd6 | ||
|
9ad85010bf | ||
|
53c08adec9 | ||
|
1ebff2c5e5 | ||
|
f75adeb2ca | ||
|
1c75adaa51 | ||
|
0c8cb94b6a | ||
|
f1d7bdaa5a | ||
|
32bd212a49 | ||
|
2c0ab9a3e9 | ||
|
d920ff7f54 | ||
|
c179b7f4b4 | ||
|
e9702ad37e | ||
|
539f217714 | ||
|
8acf7a9113 | ||
|
93b5fce168 | ||
|
2fd88b8219 | ||
|
fbf1b09514 | ||
|
22e550ee67 | ||
|
049c58c40c | ||
|
99dfc12a67 | ||
|
6e8aa9bee6 | ||
|
9590df3ef0 | ||
|
b162ed889b | ||
|
df4435efdc | ||
|
0b516fd7e2 | ||
|
4008133a0b | ||
|
bc3024881f | ||
|
c530cf20fd | ||
|
0a9a3c7129 | ||
|
a5f5c30157 | ||
|
29b2f91762 | ||
|
6211f81535 | ||
|
eb0d40a2ad | ||
|
e4136437c6 | ||
|
0c552807ff | ||
|
5bf7cf89c3 | ||
|
2f72a8004a | ||
|
484f0f68a1 | ||
|
114b66dd5c | ||
|
efca612a20 | ||
|
ae6ec7f233 | ||
|
7f397b2c2c | ||
|
98bd980c2a | ||
|
a7c2f52814 | ||
|
a386ab7df0 | ||
|
886da1a134 | ||
|
07898d31b9 | ||
|
f3191a6067 | ||
|
0c52d44d3e | ||
|
c7caf52f3e | ||
|
643313baa0 | ||
|
ebe1815075 | ||
|
e9b0269c91 | ||
|
d1bac84663 | ||
|
7023e2e1fe | ||
|
4ac444be47 | ||
|
9633ee3f72 | ||
|
3a74ef5e21 | ||
|
416ed28206 | ||
|
80754593ad | ||
|
2685f49d24 | ||
|
fe430bbb19 | ||
|
6ea43c35e0 | ||
|
031ca32ab0 | ||
|
c4d8e8de6b | ||
|
02c6f58f3c | ||
|
874882d926 | ||
|
0a71a954c2 | ||
|
5e0e3e0e22 | ||
|
bd0b80827e | ||
|
eb105690b5 | ||
|
8425ed5a3b | ||
|
91740c8573 | ||
|
f247bba985 | ||
|
0425becba9 | ||
|
fb6faaff1a | ||
|
d575bf7607 | ||
|
01d377555a | ||
|
dd9b84258b | ||
|
f41253d9ca | ||
|
d6486b590a | ||
|
c24a1ca633 | ||
|
a8e870cc87 | ||
|
6c452a91e7 | ||
|
cc763de706 | ||
|
eaece3db50 | ||
|
ed2405f46b | ||
|
85319d7f27 | ||
|
011a33ff43 | ||
|
2bc4637f5c | ||
|
f1003ef9d5 | ||
|
b88267c828 | ||
|
7c4d622d8a | ||
|
f3b8858727 | ||
|
bff66e2b72 | ||
|
358c6b1c78 | ||
|
cd28d82939 | ||
|
a5856ecd6d | ||
|
0c40e8a6fc | ||
|
3436afcf18 | ||
|
e26391bc2f | ||
|
f09f62e441 | ||
|
47673877f0 | ||
|
05209793be | ||
|
20154ba519 | ||
|
8b99aa30f3 | ||
|
ed0342b955 | ||
|
b40b2a2f01 | ||
|
7e15c40849 | ||
|
a113c5540d | ||
|
3f5693cf43 | ||
|
ca1a490bbb | ||
|
8711f8cae7 | ||
|
417a334fc0 | ||
|
7dc9e68367 | ||
|
46b63fc871 | ||
|
ffa5d7e611 | ||
|
0f3fe14aa3 | ||
|
7ae6968b5c | ||
|
c5c8c163af | ||
|
361f915cce | ||
|
1e044c140d | ||
|
5d1b73b3a2 | ||
|
867ce85fee | ||
|
69e0161ce4 | ||
|
81abff3d75 | ||
|
8e80e04a33 | ||
|
429c699c00 | ||
|
47d703cb1e | ||
|
a6373e66c9 | ||
|
617d30d804 | ||
|
f9df8b22ef |
20
Makefile
20
Makefile
@ -21,6 +21,10 @@ KRKMODS = $(wildcard modules/*.krk modules/*/*.krk modules/*/*/*.krk)
|
||||
|
||||
all: ${TARGET} ${MODULES} ${TOOLS} ${GENMODS}
|
||||
|
||||
ifneq ($(shell tools/can-floor-without-libm.sh "$(CC) $(filter-out -g,$(CFLAGS))"),yes)
|
||||
LDLIBS += -lm
|
||||
endif
|
||||
|
||||
ifeq (,$(findstring mingw,$(CC)))
|
||||
CFLAGS += -pthread
|
||||
LDLIBS += -ldl -lpthread
|
||||
@ -72,10 +76,25 @@ ifdef KRK_NO_STRESS_GC
|
||||
CFLAGS += -DKRK_NO_STRESS_GC=1
|
||||
endif
|
||||
|
||||
ifdef KRK_NO_FLOAT
|
||||
CFLAGS += -DKRK_NO_FLOAT=1
|
||||
endif
|
||||
|
||||
ifdef KRK_HEAP_TAG_BYTE
|
||||
CFLAGS += -DKRK_HEAP_TAG_BYTE=${KRK_HEAP_TAG_BYTE}
|
||||
endif
|
||||
|
||||
ifdef KRK_NO_NAN_BOXING
|
||||
CFLAGS += -DKRK_NO_NAN_BOXING=1
|
||||
endif
|
||||
|
||||
ifdef KRK_BUNDLE_LIBS
|
||||
KRK_BUNDLE_LIBS_CFLAG=$(patsubst %,BUNDLED(%);,${KRK_BUNDLE_LIBS})
|
||||
KRK_BUNDLE_LIBS_BOBJS=$(patsubst %,src/modules/module_%.o,${KRK_BUNDLE_LIBS})
|
||||
BIN_OBJS += ${KRK_BUNDLE_LIBS_BOBJS}
|
||||
CFLAGS += -DKRK_BUNDLE_LIBS="${KRK_BUNDLE_LIBS_CFLAG}"
|
||||
endif
|
||||
|
||||
.PHONY: help
|
||||
|
||||
help:
|
||||
@ -114,6 +133,7 @@ src/debug.o: src/opcodes.h
|
||||
src/value.o: src/opcodes.h
|
||||
src/vm.o: src/opcodes.h
|
||||
src/exceptions.o: src/opcodes.h
|
||||
modules/dis.so: src/opcodes.h
|
||||
|
||||
|
||||
%.o: %.c ${HEADERS}
|
||||
|
@ -45,8 +45,6 @@ Halts execution and calls the debugger before every instruction.
|
||||
Prints a message each time the garbage collector is run.
|
||||
- `KRK_GLOBAL_ENABLE_STRESS_GC`
|
||||
Causes the garbage collector to be called on every allocation (from the main thread).
|
||||
- `KRK_GLOBAL_CALLGRIND`
|
||||
Generate tracing data. `vm.callgrindFile` must be set to a writable stream to store the intermediate data collected by the VM.
|
||||
- `KRK_GLOBAL_CLEAN_OUTPUT`
|
||||
Disables automatic printing of uncaught exception tracebacks. Use `krk_dumpTraceback()` to print a traceback from the exception in the current thread to `stderr`.
|
||||
|
||||
|
@ -1,65 +0,0 @@
|
||||
'''
|
||||
@brief Tool to process VM trace reports and generate callgrind-formatted output.
|
||||
'''
|
||||
import kuroko
|
||||
import fileio
|
||||
|
||||
def processFile(sourcePath: str, pid: int , cmd: str):
|
||||
'''@brief Process @p sourcePath from process @p pid with command @p cmd as a VM trace file.'''
|
||||
let funcs = {}
|
||||
|
||||
with fileio.open(sourcePath,'r') as f:
|
||||
for line in f.readlines():
|
||||
let callerFile, callerFunc, callerLine, calleeFile, calleeFunc, calleeLine, nsecs = line.split(' ')
|
||||
nsecs = float(nsecs)
|
||||
let data = funcs.get((callerFile,callerFunc),{})
|
||||
let call = data.get((callerLine,calleeFile,calleeFunc,calleeLine),(0,0))
|
||||
let out = (call[0] + 1, call[1] + nsecs)
|
||||
data[callerLine,calleeFile,calleeFunc,calleeLine] = out
|
||||
funcs[callerFile,callerFunc] = data
|
||||
let called = funcs.get((calleeFile,calleeFunc),{})
|
||||
let times = called.get(None,(1,0))
|
||||
called[None] = (calleeLine, times[1] + nsecs)
|
||||
funcs[calleeFile,calleeFunc] = called
|
||||
|
||||
with fileio.open(f'callgrind.out.{pid}','w') as out:
|
||||
out.write('# callgrind format\n')
|
||||
out.write('creator: Kuroko\n')
|
||||
out.write('positions: line\n')
|
||||
out.write('events: nanoseconds\n')
|
||||
out.write(f'cmd: {cmd}\n\n')
|
||||
|
||||
def defloat(f):
|
||||
let s = int(f)
|
||||
let n = str(int(f * 1000000000))
|
||||
if len(n) > 9: n = n[-9:]
|
||||
let o = (str(s) + '0' * (9 - len(n)) + n).lstrip('0')
|
||||
return o if o else '0'
|
||||
|
||||
def cleanfunc(func):
|
||||
for s in ['<module>','<listcomp>','<setcomp>','<dictcomp>','<lambda>']:
|
||||
func = func.replace(s,'['+s[1:-1]+']')
|
||||
return func.replace('@','<') + '>'
|
||||
|
||||
for key, value in funcs.items():
|
||||
let sFile, sFunc = key
|
||||
out.write(f'fl={sFile}\n')
|
||||
out.write(f'fn={cleanfunc(sFunc)}\n')
|
||||
if not sFunc.startswith('(root)'):
|
||||
let startLine, totalNsecs = value[None]
|
||||
for k, v in value.items():
|
||||
if not k: continue
|
||||
let sourceLine, file, func, destLine = k
|
||||
let count, nsecs = v
|
||||
totalNsecs -= nsecs
|
||||
|
||||
out.write(f'{startLine} {defloat(totalNsecs)}\n')
|
||||
for k, v in value.items():
|
||||
if not k: continue
|
||||
let sourceLine, file, func, destLine = k
|
||||
let count, totalNsecs = v
|
||||
if file != sFile: out.write(f'cfi={file}\n')
|
||||
out.write(f'cfn={cleanfunc(func)}\n')
|
||||
out.write(f'calls={count} {destLine}\n')
|
||||
out.write(f'{sourceLine} {defloat(totalNsecs)}\n')
|
||||
out.write('\n')
|
@ -1,28 +0,0 @@
|
||||
'''
|
||||
@brief Called when 'dis' is run as the main module (-m dis)
|
||||
'''
|
||||
# Get the real dis
|
||||
import dis
|
||||
|
||||
def disrec(code, seen):
|
||||
let next = [code]
|
||||
while next:
|
||||
let co = next[0]
|
||||
next = next[1:]
|
||||
dis.dis(co)
|
||||
for inst,size,operand in dis.examine(co):
|
||||
if isinstance(operand,codeobject) and operand not in seen and operand not in next:
|
||||
next.append(operand)
|
||||
if next:
|
||||
print()
|
||||
|
||||
if __name__ == '__main__':
|
||||
import kuroko
|
||||
if (len(kuroko.argv) < 2):
|
||||
print("Usage: kuroko -m dis FILE")
|
||||
return 1
|
||||
import fileio
|
||||
for file in kuroko.argv[1:]:
|
||||
with fileio.open(file,'r') as f:
|
||||
let result = dis.build(f.read(), file)
|
||||
disrec(result,set())
|
104
modules/pheap.krk
Normal file
104
modules/pheap.krk
Normal file
@ -0,0 +1,104 @@
|
||||
'''
|
||||
@brief Pairing heap.
|
||||
@author K. Lange <klange@toaruos.org>
|
||||
|
||||
Provides a simple min-heap with insert, pop, peek, and visit.
|
||||
|
||||
A Kuroko implementation is provided as a backup alongside a
|
||||
faster C implementation in a shared object module.
|
||||
'''
|
||||
|
||||
def __make_pheap():
|
||||
def pheap_meld(left, right, comp):
|
||||
if left is None:
|
||||
return right
|
||||
if right is None:
|
||||
return left
|
||||
if comp(left[0],right[0]):
|
||||
if left[1]:
|
||||
right[2] = left[1]
|
||||
left[1] = right
|
||||
return left
|
||||
else:
|
||||
if right[1]:
|
||||
left[2] = right[1]
|
||||
right[1] = left
|
||||
return right
|
||||
|
||||
def pheap_merge_pairs(lst, comp):
|
||||
if lst is None:
|
||||
return None
|
||||
else if lst[2] is None:
|
||||
return lst
|
||||
else:
|
||||
let next = lst[2]
|
||||
lst[2] = None
|
||||
let rest = next[2]
|
||||
next[2] = None
|
||||
return pheap_meld(pheap_meld(lst,next,comp), pheap_merge_pairs(rest, comp), comp)
|
||||
|
||||
def pheap_delete_min(heap, comp):
|
||||
let subs = heap[1]
|
||||
return pheap_merge_pairs(subs, comp)
|
||||
|
||||
def pheap_visit_heap(heap, func):
|
||||
if not heap: return
|
||||
func(heap)
|
||||
pheap_visit_heap(heap[1], func)
|
||||
pheap_visit_heap(heap[2], func)
|
||||
|
||||
def pheap_visit_heap_after(heap, func):
|
||||
if not heap: return
|
||||
pheap_visit_heap(heap[1], func)
|
||||
pheap_visit_heap(heap[2], func)
|
||||
func(heap)
|
||||
|
||||
class PHeap:
|
||||
def __init__(self, comp):
|
||||
'''Create a new pairing heap governed by the given comparator function.'''
|
||||
self.heap = None
|
||||
self.comp = comp
|
||||
self.count = 0
|
||||
|
||||
def insert(self, value):
|
||||
'''Insert a new element into the heap.'''
|
||||
self.heap = pheap_meld(self.heap, [value, None, None], self.comp)
|
||||
self.count += 1
|
||||
|
||||
def peek(self):
|
||||
'''Retrieve the root (smallest) element of the heap, or None if it is empty.'''
|
||||
return self.heap[0] if self.heap else None
|
||||
|
||||
def pop(self):
|
||||
'''Remove and return the root (smallest) element of the heap. If the heap is empty, IndexError is raised.'''
|
||||
let out = self.heap
|
||||
if not out:
|
||||
raise IndexError('pop from empty heap')
|
||||
self.heap = pheap_delete_min(self.heap, self.comp)
|
||||
self.count -= 1
|
||||
return out[0] if out else None
|
||||
|
||||
def __bool__(self):
|
||||
return self.heap is not None
|
||||
|
||||
def __len__(self):
|
||||
return self.count
|
||||
|
||||
def visit(self, func, after=False):
|
||||
'''Call a function for each element of the heap.'''
|
||||
(pheap_visit_heap_after if after else pheap_visit_heap)(self.heap, func)
|
||||
|
||||
# Clean up qualified name.
|
||||
PHeap.__qualname__ = 'PHeap'
|
||||
|
||||
return PHeap
|
||||
|
||||
# Keep the Kuroko version available for testing.
|
||||
let PHeap_krk = __make_pheap()
|
||||
let PHeap = PHeap_krk
|
||||
|
||||
# Try to load the C implementation.
|
||||
try:
|
||||
import _pheap
|
||||
PHeap = _pheap.PHeap
|
||||
|
377
src/builtins.c
377
src/builtins.c
@ -88,8 +88,15 @@ KRK_Method(object,__dir__) {
|
||||
}
|
||||
|
||||
KRK_Method(object,__class__) {
|
||||
if (argc > 1) return krk_runtimeError(vm.exceptions->typeError, "__class__ can not be assigned");
|
||||
return OBJECT_VAL(krk_getType(self));
|
||||
KrkClass * current = krk_getType(self);
|
||||
if (argc > 1) {
|
||||
if (!IS_CLASS(argv[1])) return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not a class", argv[1]);
|
||||
if (!IS_INSTANCE(argv[0]) || current->allocSize != sizeof(KrkInstance)) return krk_runtimeError(vm.exceptions->typeError, "'%T' object does not have modifiable type", argv[0]); /* TODO class? */
|
||||
if (AS_CLASS(argv[1])->allocSize != sizeof(KrkInstance)) return krk_runtimeError(vm.exceptions->typeError, "'%S' type is not assignable", AS_CLASS(argv[1])->name);
|
||||
AS_INSTANCE(argv[0])->_class = AS_CLASS(argv[1]);
|
||||
current = AS_CLASS(argv[1]);
|
||||
}
|
||||
return OBJECT_VAL(current);
|
||||
}
|
||||
|
||||
KRK_Method(object,__hash__) {
|
||||
@ -100,7 +107,7 @@ KRK_Method(object,__hash__) {
|
||||
}
|
||||
KrkObj * obj = AS_OBJECT(self);
|
||||
if (!(obj->flags & KRK_OBJ_FLAGS_VALID_HASH)) {
|
||||
obj->hash = INTEGER_VAL((int)((intptr_t)self >> 3));
|
||||
obj->hash = (uint32_t)((intptr_t)(obj) >> 3);
|
||||
obj->flags |= KRK_OBJ_FLAGS_VALID_HASH;
|
||||
}
|
||||
return INTEGER_VAL(obj->hash);
|
||||
@ -108,7 +115,7 @@ KRK_Method(object,__hash__) {
|
||||
|
||||
KRK_Method(object,__eq__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
if (argv[0] == argv[1]) return BOOLEAN_VAL(1);
|
||||
if (krk_valuesSame(argv[0],argv[1])) return BOOLEAN_VAL(1);
|
||||
return NOTIMPL_VAL();
|
||||
}
|
||||
|
||||
@ -177,6 +184,42 @@ KRK_Method(object,__setattr__) {
|
||||
return krk_instanceSetAttribute_wrapper(argv[0], AS_STRING(argv[1]), argv[2]);
|
||||
}
|
||||
|
||||
KRK_StaticMethod(object,__new__) {
|
||||
KrkClass * _class = NULL;
|
||||
|
||||
/* We don't actually care, but we want to accept them anyway */
|
||||
int _argc = 0;
|
||||
const KrkValue * _args = NULL;
|
||||
|
||||
if (!krk_parseArgs("O!*~", (const char*[]){"cls"}, vm.baseClasses->typeClass, &_class, &_argc, &_args)) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KrkClass * _cls = _class;
|
||||
while (_cls) {
|
||||
if (_cls->_new && IS_NATIVE(OBJECT_VAL(_cls->_new)) && _cls->_new != KRK_BASE_CLASS(object)->_new) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "object.__new__(%S) is not safe, use %S.__new__()", _class->name, _cls->name);
|
||||
}
|
||||
_cls = _cls->base;
|
||||
}
|
||||
|
||||
if (_class->_init == vm.baseClasses->objectClass->_init && (_argc || (hasKw && AS_DICT(argv[argc])->count))) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "%S() takes no arguments", _class->name);
|
||||
}
|
||||
|
||||
return OBJECT_VAL(krk_newInstance(_class));
|
||||
}
|
||||
|
||||
KRK_Method(object,__init__) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_StaticMethod(object,__init_subclass__) {
|
||||
if (!krk_parseArgs(".", (const char*[]){NULL}, NULL)) return NONE_VAL();
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* object.__str__() / object.__repr__()
|
||||
*
|
||||
@ -190,7 +233,7 @@ KRK_Method(object,__setattr__) {
|
||||
* all types should have a string representation available through
|
||||
* those methods.
|
||||
*/
|
||||
KRK_Method(object,__str__) {
|
||||
KRK_Method(object,__repr__) {
|
||||
KrkClass * type = krk_getType(self);
|
||||
|
||||
KrkValue module = NONE_VAL();
|
||||
@ -219,6 +262,13 @@ _error:
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(object,__str__) {
|
||||
KrkClass * type = krk_getType(self);
|
||||
if (unlikely(!type->_reprer)) return krk_runtimeError(vm.exceptions->typeError, "object is not representable");
|
||||
krk_push(self);
|
||||
return krk_callDirect(type->_reprer, 1);
|
||||
}
|
||||
|
||||
KRK_Method(object,__format__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
if (!IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]);
|
||||
@ -266,7 +316,7 @@ KRK_Function(dir) {
|
||||
|
||||
/* Put all the keys from the globals table in it */
|
||||
KrkTable * globals = krk_currentThread.frames[krk_currentThread.frameCount-1].globals;
|
||||
for (size_t i = 0; i < globals->capacity; ++i) {
|
||||
for (size_t i = 0; i < globals->used; ++i) {
|
||||
KrkTableEntry * entry = &globals->entries[i];
|
||||
if (IS_KWARGS(entry->key)) continue;
|
||||
krk_writeValueArray(AS_LIST(myList), entry->key);
|
||||
@ -313,19 +363,19 @@ KRK_Function(chr) {
|
||||
|
||||
KRK_Function(hex) {
|
||||
FUNCTION_TAKES_EXACTLY(1);
|
||||
trySlowMethod(OBJECT_VAL(S("__hex__")));
|
||||
trySlowMethod(vm.specialMethodNames[METHOD_HEX]);
|
||||
return TYPE_ERROR(int,argv[0]);
|
||||
}
|
||||
|
||||
KRK_Function(oct) {
|
||||
FUNCTION_TAKES_EXACTLY(1);
|
||||
trySlowMethod(OBJECT_VAL(S("__oct__")));
|
||||
trySlowMethod(vm.specialMethodNames[METHOD_OCT]);
|
||||
return TYPE_ERROR(int,argv[0]);
|
||||
}
|
||||
|
||||
KRK_Function(bin) {
|
||||
FUNCTION_TAKES_EXACTLY(1);
|
||||
trySlowMethod(OBJECT_VAL(S("__bin__")));
|
||||
trySlowMethod(vm.specialMethodNames[METHOD_BIN]);
|
||||
return TYPE_ERROR(int,argv[0]);
|
||||
}
|
||||
|
||||
@ -340,7 +390,7 @@ int krk_unpackIterable(KrkValue iterable, void * context, int callback(void *, c
|
||||
} else if (IS_list(iterable)) {
|
||||
if (callback(context, AS_LIST(iterable)->values, AS_LIST(iterable)->count)) return 1;
|
||||
} else if (IS_dict(iterable)) {
|
||||
for (size_t i = 0; i < AS_DICT(iterable)->capacity; ++i) {
|
||||
for (size_t i = 0; i < AS_DICT(iterable)->used; ++i) {
|
||||
if (!IS_KWARGS(AS_DICT(iterable)->entries[i].key)) {
|
||||
if (callback(context, &AS_DICT(iterable)->entries[i].key, 1)) return 1;
|
||||
}
|
||||
@ -471,7 +521,7 @@ KRK_Method(map,__init__) {
|
||||
iters->values.values[iters->values.count++] = asIter;
|
||||
}
|
||||
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(map,__iter__) {
|
||||
@ -535,7 +585,7 @@ KRK_Method(zip,__init__) {
|
||||
iters->values.values[iters->values.count++] = asIter;
|
||||
}
|
||||
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(zip,__iter__) {
|
||||
@ -582,7 +632,8 @@ KRK_Method(filter,__init__) {
|
||||
KrkValue asIter = krk_callDirect(type->_iter, 1);
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
krk_attachNamedValue(&self->fields, "_iterator", asIter);
|
||||
return argv[0];
|
||||
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(filter,__iter__) {
|
||||
@ -633,23 +684,23 @@ KRK_Method(filter,__call__) {
|
||||
#define IS_enumerate(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(enumerate)))
|
||||
#define AS_enumerate(o) (AS_INSTANCE(o))
|
||||
KRK_Method(enumerate,__init__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
KrkValue iterator;
|
||||
KrkValue start = INTEGER_VAL(0);
|
||||
if (hasKw) krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("start")), &start);
|
||||
if (!krk_parseArgs(".V|V", (const char*[]){"iterable","start"}, &iterator, &start)) return NONE_VAL();
|
||||
|
||||
krk_attachNamedValue(&self->fields, "_counter", start);
|
||||
|
||||
/* Attach iterator */
|
||||
KrkClass * type = krk_getType(argv[1]);
|
||||
KrkClass * type = krk_getType(iterator);
|
||||
if (!type->_iter) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", argv[1]);
|
||||
return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", iterator);
|
||||
}
|
||||
krk_push(argv[1]);
|
||||
krk_push(iterator);
|
||||
KrkValue asIter = krk_callDirect(type->_iter, 1);
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
krk_attachNamedValue(&self->fields, "_iterator", asIter);
|
||||
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(enumerate,__iter__) {
|
||||
@ -706,13 +757,11 @@ static int _sum_callback(void * context, const KrkValue * values, size_t count)
|
||||
}
|
||||
|
||||
KRK_Function(sum) {
|
||||
FUNCTION_TAKES_AT_LEAST(1);
|
||||
KrkValue iterable;
|
||||
KrkValue base = INTEGER_VAL(0);
|
||||
if (hasKw) {
|
||||
krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("start")), &base);
|
||||
}
|
||||
if (!krk_parseArgs("V|$V", (const char*[]){"iterable","start"}, &iterable, &base)) return NONE_VAL();
|
||||
struct SimpleContext context = { base };
|
||||
if (krk_unpackIterable(argv[0], &context, _sum_callback)) return NONE_VAL();
|
||||
if (krk_unpackIterable(iterable, &context, _sum_callback)) return NONE_VAL();
|
||||
return context.base;
|
||||
}
|
||||
|
||||
@ -767,42 +816,81 @@ KRK_Function(max) {
|
||||
}
|
||||
|
||||
KRK_Function(print) {
|
||||
KrkValue sepVal;
|
||||
KrkValue endVal;
|
||||
char * sep = " "; size_t sepLen = 1;
|
||||
char * end = "\n"; size_t endLen = 1;
|
||||
if (hasKw) {
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("sep")), &sepVal)) {
|
||||
if (!IS_STRING(sepVal)) return krk_runtimeError(vm.exceptions->typeError, "'%s' should be a string, not '%T'", "sep", sepVal);
|
||||
sep = AS_CSTRING(sepVal);
|
||||
sepLen = AS_STRING(sepVal)->length;
|
||||
}
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("end")), &endVal)) {
|
||||
if (!IS_STRING(endVal)) return krk_runtimeError(vm.exceptions->typeError, "'%s' should be a string, not '%T'", "end", endVal);
|
||||
end = AS_CSTRING(endVal);
|
||||
endLen = AS_STRING(endVal)->length;
|
||||
}
|
||||
char * sep = NULL;
|
||||
char * end = NULL;
|
||||
size_t sepLen = 0;
|
||||
size_t endLen = 0;
|
||||
int remArgc;
|
||||
const KrkValue * remArgv;
|
||||
KrkValue file = NONE_VAL();
|
||||
int flush = 0;
|
||||
|
||||
if (!krk_parseArgs("*z#z#Vp", (const char*[]){"sep","end","file","flush"},
|
||||
&remArgc, &remArgv,
|
||||
&sep, &sepLen, &end, &endLen,
|
||||
&file, &flush)) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
if (!argc) {
|
||||
for (size_t j = 0; j < endLen; ++j) {
|
||||
fputc(end[j], stdout);
|
||||
|
||||
/* Set default separator and end if not provided or set to None. */
|
||||
if (!sep) { sep = " "; sepLen = 1; }
|
||||
if (!end) { end = "\n"; endLen = 1; }
|
||||
|
||||
for (int i = 0; i < remArgc; ++i) {
|
||||
|
||||
/* If printing through a file object, get its @c write method */
|
||||
if (!IS_NONE(file)) {
|
||||
krk_push(krk_valueGetAttribute(file, "write"));
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
KrkValue printable = argv[i];
|
||||
if (IS_STRING(printable)) { /* krk_printValue runs repr */
|
||||
/* Make sure we handle nil bits correctly. */
|
||||
for (size_t j = 0; j < AS_STRING(printable)->length; ++j) {
|
||||
fputc(AS_CSTRING(printable)[j], stdout);
|
||||
|
||||
/* Convert the argument to a printable form, first by trying __str__, then __repr__ */
|
||||
KrkValue printable = remArgv[i];
|
||||
krk_push(printable);
|
||||
if (!IS_STRING(printable)) {
|
||||
KrkClass * type = krk_getType(printable);
|
||||
if (type->_tostr) {
|
||||
krk_push((printable = krk_callDirect(type->_tostr, 1)));
|
||||
} else if (type->_reprer) {
|
||||
krk_push((printable = krk_callDirect(type->_reprer, 1)));
|
||||
}
|
||||
if (!IS_STRING(printable)) return krk_runtimeError(vm.exceptions->typeError, "__str__ returned non-string (type %T)", printable);
|
||||
}
|
||||
|
||||
if (!IS_NONE(file)) {
|
||||
/* Call @c write */
|
||||
krk_callStack(1);
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
|
||||
/* Print separator */
|
||||
if (i + 1 < remArgc) {
|
||||
krk_push(krk_valueGetAttribute(file, "write"));
|
||||
krk_push(OBJECT_VAL(krk_copyString(sep,sepLen)));
|
||||
krk_callStack(1);
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
}
|
||||
} else {
|
||||
krk_printValue(stdout, printable);
|
||||
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return NONE_VAL();
|
||||
fwrite(AS_CSTRING(printable), AS_STRING(printable)->length, 1, stdout);
|
||||
krk_pop();
|
||||
if (i + 1 < remArgc) fwrite(sep, sepLen, 1, stdout);
|
||||
}
|
||||
char * thingToPrint = (i == argc - 1) ? end : sep;
|
||||
for (size_t j = 0; j < ((i == argc - 1) ? endLen : sepLen); ++j) {
|
||||
fputc(thingToPrint[j], stdout);
|
||||
}
|
||||
|
||||
if (!IS_NONE(file)) {
|
||||
/* Print end */
|
||||
krk_push(krk_valueGetAttribute(file, "write"));
|
||||
krk_push(OBJECT_VAL(krk_copyString(end,endLen)));
|
||||
krk_callStack(1);
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
|
||||
/* Maybe flush */
|
||||
if (flush) {
|
||||
krk_push(krk_valueGetAttribute(file, "flush"));
|
||||
krk_callStack(0);
|
||||
}
|
||||
}else {
|
||||
fwrite(end, endLen, 1, stdout);
|
||||
if (flush) fflush(stdout);
|
||||
}
|
||||
|
||||
return NONE_VAL();
|
||||
@ -905,22 +993,14 @@ KRK_Function(isinstance) {
|
||||
}
|
||||
}
|
||||
|
||||
static int _isSubClass(KrkClass * cls, KrkClass * base) {
|
||||
while (cls) {
|
||||
if (cls == base) return 1;
|
||||
cls = cls->base;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
KRK_Function(issubclass) {
|
||||
FUNCTION_TAKES_EXACTLY(2);
|
||||
CHECK_ARG(0,class,KrkClass*,cls);
|
||||
if (IS_CLASS(argv[1])) {
|
||||
return BOOLEAN_VAL(_isSubClass(cls, AS_CLASS(argv[1])));
|
||||
return BOOLEAN_VAL(krk_isSubClass(cls, AS_CLASS(argv[1])));
|
||||
} else if (IS_TUPLE(argv[1])) {
|
||||
for (size_t i = 0; i < AS_TUPLE(argv[1])->values.count; ++i) {
|
||||
if (IS_CLASS(AS_TUPLE(argv[1])->values.values[i]) && _isSubClass(cls, AS_CLASS(AS_TUPLE(argv[1])->values.values[i]))) {
|
||||
if (IS_CLASS(AS_TUPLE(argv[1])->values.values[i]) && krk_isSubClass(cls, AS_CLASS(AS_TUPLE(argv[1])->values.values[i]))) {
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
}
|
||||
@ -1055,7 +1135,7 @@ KRK_Method(property,__init__) {
|
||||
((struct Property*)self)->fset = IS_OBJECT(argv[2]) ? AS_OBJECT(argv[2]) : NULL;
|
||||
}
|
||||
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(property,setter) {
|
||||
@ -1065,7 +1145,9 @@ KRK_Method(property,setter) {
|
||||
}
|
||||
|
||||
KRK_Method(property,__get__) {
|
||||
METHOD_TAKES_EXACTLY(1); /* the owner */
|
||||
METHOD_TAKES_AT_LEAST(1); /* the owner */
|
||||
|
||||
if (IS_NONE(argv[1])) return argv[0];
|
||||
|
||||
struct Property * asProp = (struct Property *)self;
|
||||
|
||||
@ -1179,11 +1261,13 @@ KRK_Function(abs) {
|
||||
if (IS_INTEGER(argv[0])) {
|
||||
krk_integer_type i = AS_INTEGER(argv[0]);
|
||||
return INTEGER_VAL(i >= 0 ? i : -i);
|
||||
#ifndef KRK_NO_FLOAT
|
||||
} else if (IS_FLOATING(argv[0])) {
|
||||
double i = AS_FLOATING(argv[0]);
|
||||
return FLOATING_VAL(i >= 0 ? i : -i);
|
||||
#endif
|
||||
} else {
|
||||
trySlowMethod(OBJECT_VAL(S("__abs__")));
|
||||
trySlowMethod(vm.specialMethodNames[METHOD_ABS]);
|
||||
return krk_runtimeError(vm.exceptions->typeError, "bad operand type for 'abs()': '%T'", argv[0]);
|
||||
}
|
||||
}
|
||||
@ -1210,14 +1294,148 @@ KRK_Function(format) {
|
||||
}
|
||||
|
||||
static void module_sweep(KrkInstance * inst) {
|
||||
#ifndef STATIC_ONLY
|
||||
#ifndef KRK_STATIC_ONLY
|
||||
struct KrkModule * module = (struct KrkModule*)inst;
|
||||
if (module->libHandle) {
|
||||
dlClose(module->libHandle);
|
||||
krk_dlClose(module->libHandle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
KRK_Function(__build_class__) {
|
||||
KrkValue func = NONE_VAL();
|
||||
KrkString * name = NULL;
|
||||
KrkClass * base = vm.baseClasses->objectClass;
|
||||
KrkValue metaclass = OBJECT_VAL(vm.baseClasses->typeClass);
|
||||
|
||||
if (!krk_parseArgs("VO!|O!$V~",
|
||||
(const char*[]){"func","name","base","metaclass"},
|
||||
&func,
|
||||
vm.baseClasses->strClass, &name,
|
||||
vm.baseClasses->typeClass, &base,
|
||||
&metaclass)) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (IS_CLASS(metaclass)) {
|
||||
KrkClass * basemeta = base->_class ? base->_class : vm.baseClasses->typeClass;
|
||||
if (krk_isSubClass(AS_CLASS(metaclass), basemeta)) {
|
||||
/* good to go */
|
||||
} else if (krk_isSubClass(basemeta, AS_CLASS(metaclass))) {
|
||||
/* take the more derived one */
|
||||
metaclass = OBJECT_VAL(basemeta);
|
||||
} else {
|
||||
return krk_runtimeError(vm.exceptions->typeError,
|
||||
"metaclass conflict: %S is not a subclass of %S", AS_CLASS(metaclass)->name, basemeta->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Push function */
|
||||
krk_push(func);
|
||||
|
||||
/* Call __prepare__ from metaclass */
|
||||
krk_push(krk_valueGetAttribute_default(metaclass, "__prepare__", KWARGS_VAL(0)));
|
||||
|
||||
/* Bail early on exception */
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
|
||||
if (IS_KWARGS(krk_peek(0))) {
|
||||
krk_pop();
|
||||
krk_push(krk_dict_of(0,NULL,0));
|
||||
} else {
|
||||
krk_push(OBJECT_VAL(name));
|
||||
krk_push(OBJECT_VAL(base));
|
||||
/* Do we have keywords? */
|
||||
int args = 2;
|
||||
if (hasKw) {
|
||||
args += 3;
|
||||
krk_push(KWARGS_VAL(KWARGS_DICT));
|
||||
krk_push(argv[argc]);
|
||||
krk_push(KWARGS_VAL(1));
|
||||
}
|
||||
krk_push(krk_callStack(args));
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
}
|
||||
|
||||
/* Run the class function on it */
|
||||
krk_push(krk_callStack(1));
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
|
||||
/* Now call the metaclass with the name, base, namespace, and kwds */
|
||||
int args = 3;
|
||||
krk_push(OBJECT_VAL(name));
|
||||
krk_push(OBJECT_VAL(base));
|
||||
krk_push(metaclass);
|
||||
krk_swap(3);
|
||||
|
||||
if (hasKw) {
|
||||
args += 3;
|
||||
krk_push(KWARGS_VAL(KWARGS_DICT));
|
||||
krk_push(argv[argc]);
|
||||
krk_push(KWARGS_VAL(1));
|
||||
}
|
||||
|
||||
krk_push(krk_callStack(args));
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
|
||||
|
||||
/* Now assign the upvalue for the original function if it's a closure. */
|
||||
if (IS_CLOSURE(func)) {
|
||||
if (AS_CLOSURE(func)->upvalueCount && AS_CLOSURE(func)->upvalues[0]->location == -1 && IS_NONE(AS_CLOSURE(func)->upvalues[0]->closed)) {
|
||||
AS_CLOSURE(func)->upvalues[0]->closed = krk_peek(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* We're done, return the resulting class object. */
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
#define CURRENT_CTYPE KrkUpvalue *
|
||||
#define IS_Cell(o) (krk_isObjType((o), KRK_OBJ_UPVALUE))
|
||||
#define AS_Cell(o) ((KrkUpvalue*)AS_OBJECT(o))
|
||||
|
||||
KRK_StaticMethod(Cell,__new__) {
|
||||
KrkClass * _class = NULL;
|
||||
KrkValue contents = NONE_VAL();
|
||||
if (!krk_parseArgs("O!|V:Cell", (const char*[]){"cls","contents"}, KRK_BASE_CLASS(type), &_class, &contents)) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
if (_class != KRK_BASE_CLASS(Cell)) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "can not assemble new Cell from %R", OBJECT_VAL(_class));
|
||||
}
|
||||
|
||||
KrkUpvalue * out = krk_newUpvalue(-1);
|
||||
out->closed = contents;
|
||||
return OBJECT_VAL(out);
|
||||
}
|
||||
|
||||
#define UPVALUE_LOCATION(upvalue) (upvalue->location == -1 ? &upvalue->closed : &upvalue->owner->stack[upvalue->location])
|
||||
KRK_Method(Cell,__repr__) {
|
||||
struct StringBuilder sb = {0};
|
||||
|
||||
KrkValue contents = *UPVALUE_LOCATION(self);
|
||||
|
||||
if (!krk_pushStringBuilderFormat(&sb,"<cell at %p: %T object", (void*)self, contents)) goto _error;
|
||||
if (IS_OBJECT(contents)) {
|
||||
if (!krk_pushStringBuilderFormat(&sb, " at %p>", (void*)AS_OBJECT(contents))) goto _error;
|
||||
} else {
|
||||
krk_pushStringBuilder(&sb,'>');
|
||||
}
|
||||
|
||||
return krk_finishStringBuilder(&sb);
|
||||
|
||||
_error:
|
||||
krk_discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(Cell,cell_contents) {
|
||||
if (argc > 1) {
|
||||
*UPVALUE_LOCATION(self) = argv[1];
|
||||
}
|
||||
return *UPVALUE_LOCATION(self);
|
||||
}
|
||||
|
||||
_noexport
|
||||
void _createAndBind_builtins(void) {
|
||||
vm.baseClasses->objectClass = krk_newClass(S("object"), NULL);
|
||||
@ -1226,11 +1444,14 @@ void _createAndBind_builtins(void) {
|
||||
KrkClass * object = vm.baseClasses->objectClass;
|
||||
BIND_METHOD(object,__dir__);
|
||||
BIND_METHOD(object,__str__);
|
||||
BIND_METHOD(object,__repr__);
|
||||
BIND_METHOD(object,__hash__);
|
||||
BIND_METHOD(object,__eq__);
|
||||
BIND_METHOD(object,__format__);
|
||||
BIND_METHOD(object,__setattr__)->obj.flags = KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
|
||||
krk_defineNative(&object->methods, "__repr__", FUNC_NAME(object,__str__));
|
||||
BIND_STATICMETHOD(object,__setattr__);
|
||||
BIND_STATICMETHOD(object,__new__);
|
||||
BIND_METHOD(object,__init__);
|
||||
BIND_CLASSMETHOD(object,__init_subclass__);
|
||||
krk_finalizeClass(object);
|
||||
KRK_DOC(object,
|
||||
"@brief Base class for all types.\n\n"
|
||||
@ -1247,7 +1468,6 @@ void _createAndBind_builtins(void) {
|
||||
krk_push(OBJECT_VAL(module));
|
||||
|
||||
BIND_METHOD(module,__repr__);
|
||||
krk_defineNative(&module->methods, "__str__", FUNC_NAME(module,__repr__));
|
||||
krk_finalizeClass(module);
|
||||
KRK_DOC(module, "Type of imported modules and packages.");
|
||||
|
||||
@ -1362,6 +1582,14 @@ void _createAndBind_builtins(void) {
|
||||
BIND_METHOD(enumerate,__call__);
|
||||
krk_finalizeClass(enumerate);
|
||||
|
||||
KrkClass * Cell = ADD_BASE_CLASS(KRK_BASE_CLASS(Cell), "Cell", object);
|
||||
Cell->allocSize = 0;
|
||||
Cell->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_STATICMETHOD(Cell,__new__);
|
||||
BIND_METHOD(Cell,__repr__);
|
||||
BIND_PROP(Cell,cell_contents);
|
||||
krk_finalizeClass(Cell);
|
||||
|
||||
BUILTIN_FUNCTION("isinstance", FUNC_NAME(krk,isinstance),
|
||||
"@brief Check if an object is an instance of a type.\n"
|
||||
"@arguments inst, cls\n\n"
|
||||
@ -1399,7 +1627,7 @@ void _createAndBind_builtins(void) {
|
||||
"@c repr strings should convey all information needed to recreate the object, if this is possible.");
|
||||
BUILTIN_FUNCTION("print", FUNC_NAME(krk,print),
|
||||
"@brief Print text to the standard output.\n"
|
||||
"@arguments *args,sep=' ',end='\\n'\n\n"
|
||||
"@arguments *args,sep=' ',end='\\n',file=None,flush=False\n\n"
|
||||
"Prints the string representation of each argument to the standard output. "
|
||||
"The keyword argument @p sep specifies the string to print between values. "
|
||||
"The keyword argument @p end specifies the string to print after all of the values have been printed.");
|
||||
@ -1488,5 +1716,8 @@ void _createAndBind_builtins(void) {
|
||||
BUILTIN_FUNCTION("format", FUNC_NAME(krk,format),
|
||||
"@brief Format a value for string printing.\n"
|
||||
"@arguments value[,format_spec]");
|
||||
BUILTIN_FUNCTION("__build_class__", FUNC_NAME(krk,__build_class__),
|
||||
"@brief Internal function to build a type object.\n"
|
||||
"@arguments func, name, base=object, metaclass=type");
|
||||
}
|
||||
|
||||
|
41
src/chunk.c
41
src/chunk.c
@ -13,6 +13,7 @@ void krk_initChunk(KrkChunk * chunk) {
|
||||
chunk->linesCapacity = 0;
|
||||
chunk->lines = NULL;
|
||||
chunk->filename = NULL;
|
||||
|
||||
krk_initValueArray(&chunk->constants);
|
||||
}
|
||||
|
||||
@ -20,8 +21,8 @@ static void addLine(KrkChunk * chunk, size_t line) {
|
||||
if (chunk->linesCount && chunk->lines[chunk->linesCount-1].line == line) return;
|
||||
if (chunk->linesCapacity < chunk->linesCount + 1) {
|
||||
int old = chunk->linesCapacity;
|
||||
chunk->linesCapacity = GROW_CAPACITY(old);
|
||||
chunk->lines = GROW_ARRAY(KrkLineMap, chunk->lines, old, chunk->linesCapacity);
|
||||
chunk->linesCapacity = KRK_GROW_CAPACITY(old);
|
||||
chunk->lines = KRK_GROW_ARRAY(KrkLineMap, chunk->lines, old, chunk->linesCapacity);
|
||||
}
|
||||
chunk->lines[chunk->linesCount] = (KrkLineMap){chunk->count, line};
|
||||
chunk->linesCount++;
|
||||
@ -30,8 +31,8 @@ static void addLine(KrkChunk * chunk, size_t line) {
|
||||
void krk_writeChunk(KrkChunk * chunk, uint8_t byte, size_t line) {
|
||||
if (chunk->capacity < chunk->count + 1) {
|
||||
int old = chunk->capacity;
|
||||
chunk->capacity = GROW_CAPACITY(old);
|
||||
chunk->code = GROW_ARRAY(uint8_t, chunk->code, old, chunk->capacity);
|
||||
chunk->capacity = KRK_GROW_CAPACITY(old);
|
||||
chunk->code = KRK_GROW_ARRAY(uint8_t, chunk->code, old, chunk->capacity);
|
||||
}
|
||||
|
||||
chunk->code[chunk->count] = byte;
|
||||
@ -40,8 +41,8 @@ void krk_writeChunk(KrkChunk * chunk, uint8_t byte, size_t line) {
|
||||
}
|
||||
|
||||
void krk_freeChunk(KrkChunk * chunk) {
|
||||
FREE_ARRAY(uint8_t, chunk->code, chunk->capacity);
|
||||
FREE_ARRAY(KrkLineMap, chunk->lines, chunk->linesCapacity);
|
||||
KRK_FREE_ARRAY(uint8_t, chunk->code, chunk->capacity);
|
||||
KRK_FREE_ARRAY(KrkLineMap, chunk->lines, chunk->linesCapacity);
|
||||
krk_freeValueArray(&chunk->constants);
|
||||
krk_initChunk(chunk);
|
||||
}
|
||||
@ -72,11 +73,29 @@ size_t krk_writeConstant(KrkChunk * chunk, KrkValue value, size_t line) {
|
||||
}
|
||||
|
||||
size_t krk_lineNumber(KrkChunk * chunk, size_t offset) {
|
||||
size_t line = 0;
|
||||
for (size_t i = 0; i < chunk->linesCount; ++i) {
|
||||
if (chunk->lines[i].startOffset > offset) break;
|
||||
line = chunk->lines[i].line;
|
||||
|
||||
size_t lo = 0;
|
||||
size_t hi = chunk->linesCount;
|
||||
|
||||
while (lo != hi) {
|
||||
if (hi - lo < 10) {
|
||||
size_t line = 0;
|
||||
for (size_t i = lo; i < hi; ++i) {
|
||||
if (chunk->lines[i].startOffset > offset) break;
|
||||
line = chunk->lines[i].line;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
size_t mp = lo + (hi - lo) / 2;
|
||||
|
||||
if (chunk->lines[mp].startOffset > offset) {
|
||||
hi = mp;
|
||||
} else {
|
||||
lo = mp;
|
||||
}
|
||||
}
|
||||
return line;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
786
src/compiler.c
786
src/compiler.c
File diff suppressed because it is too large
Load Diff
523
src/debug.c
523
src/debug.c
@ -12,6 +12,109 @@
|
||||
#ifndef KRK_DISABLE_DEBUG
|
||||
#define NOOP (void)0
|
||||
|
||||
#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
|
||||
#pragma GCC optimize ("Os")
|
||||
#endif
|
||||
|
||||
#define STRING_DEBUG_TRUNCATE 50
|
||||
|
||||
void krk_printValueSafe(FILE * f, KrkValue printable) {
|
||||
if (!IS_OBJECT(printable)) {
|
||||
switch (KRK_VAL_TYPE(printable)) {
|
||||
case KRK_VAL_INTEGER: fprintf(f, PRIkrk_int, AS_INTEGER(printable)); break;
|
||||
case KRK_VAL_BOOLEAN: fprintf(f, "%s", AS_BOOLEAN(printable) ? "True" : "False"); break;
|
||||
case KRK_VAL_NONE: fprintf(f, "None"); break;
|
||||
case KRK_VAL_HANDLER:
|
||||
switch (AS_HANDLER_TYPE(printable)) {
|
||||
case OP_PUSH_TRY: fprintf(f, "{try->%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_PUSH_WITH: fprintf(f, "{with->%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_RAISE: fprintf(f, "{raise<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_FILTER_EXCEPT: fprintf(f, "{except<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_BEGIN_FINALLY: fprintf(f, "{finally<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_RETURN: fprintf(f, "{return<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_END_FINALLY: fprintf(f, "{end<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_EXIT_LOOP: fprintf(f, "{exit<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_RAISE_FROM: fprintf(f, "{reraise<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
}
|
||||
break;
|
||||
case KRK_VAL_KWARGS: {
|
||||
if (AS_INTEGER(printable) == KWARGS_SINGLE) {
|
||||
fprintf(f, "{unpack single}");
|
||||
} else if (AS_INTEGER(printable) == KWARGS_LIST) {
|
||||
fprintf(f, "{unpack list}");
|
||||
} else if (AS_INTEGER(printable) == KWARGS_DICT) {
|
||||
fprintf(f, "{unpack dict}");
|
||||
} else if (AS_INTEGER(printable) == KWARGS_NIL) {
|
||||
fprintf(f, "{unpack nil}");
|
||||
} else if (AS_INTEGER(printable) == KWARGS_UNSET) {
|
||||
fprintf(f, "{unset default}");
|
||||
} else {
|
||||
fprintf(f, "{sentinel=" PRIkrk_int "}",AS_INTEGER(printable));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
#ifndef KRK_NO_FLOAT
|
||||
if (IS_FLOATING(printable)) fprintf(f, "%.16g", AS_FLOATING(printable));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
} else if (IS_STRING(printable)) {
|
||||
fprintf(f, "'");
|
||||
/*
|
||||
* Print at most STRING_DEBUG_TRUNCATE characters, as bytes, escaping anything not ASCII.
|
||||
* See also str.__repr__ which does something similar with escape sequences, but this
|
||||
* is a dumber, safer, and slightly faster approach.
|
||||
*/
|
||||
for (size_t c = 0; c < AS_STRING(printable)->length && c < STRING_DEBUG_TRUNCATE; ++c) {
|
||||
unsigned char byte = (unsigned char)AS_CSTRING(printable)[c];
|
||||
switch (byte) {
|
||||
case '\\': fprintf(f, "\\\\"); break;
|
||||
case '\n': fprintf(f, "\\n"); break;
|
||||
case '\r': fprintf(f, "\\r"); break;
|
||||
case '\'': fprintf(f, "\\'"); break;
|
||||
default: {
|
||||
if (byte < ' ' || byte > '~') {
|
||||
fprintf(f, "\\x%02x", byte);
|
||||
} else {
|
||||
fprintf(f, "%c", byte);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AS_STRING(printable)->length > STRING_DEBUG_TRUNCATE) {
|
||||
fprintf(f,"...");
|
||||
}
|
||||
fprintf(f,"'");
|
||||
} else {
|
||||
switch (AS_OBJECT(printable)->type) {
|
||||
case KRK_OBJ_CODEOBJECT: fprintf(f, "<codeobject %s>", AS_codeobject(printable)->name ? AS_codeobject(printable)->name->chars : "?"); break;
|
||||
case KRK_OBJ_CLASS: fprintf(f, "<class %s>", AS_CLASS(printable)->name ? AS_CLASS(printable)->name->chars : "?"); break;
|
||||
case KRK_OBJ_INSTANCE: fprintf(f, "<instance of %s>", AS_INSTANCE(printable)->_class->name->chars); break;
|
||||
case KRK_OBJ_NATIVE: fprintf(f, "<nativefn %s>", ((KrkNative*)AS_OBJECT(printable))->name); break;
|
||||
case KRK_OBJ_CLOSURE: fprintf(f, "<function %s>", AS_CLOSURE(printable)->function->name->chars); break;
|
||||
case KRK_OBJ_BYTES: fprintf(f, "<bytes of len %ld>", (long)AS_BYTES(printable)->length); break;
|
||||
case KRK_OBJ_TUPLE: {
|
||||
fprintf(f, "(");
|
||||
for (size_t i = 0; i < AS_TUPLE(printable)->values.count; ++i) {
|
||||
krk_printValueSafe(f, AS_TUPLE(printable)->values.values[i]);
|
||||
if (i + 1 != AS_TUPLE(printable)->values.count) {
|
||||
fprintf(f, ",");
|
||||
}
|
||||
}
|
||||
fprintf(f, ")");
|
||||
} break;
|
||||
case KRK_OBJ_BOUND_METHOD: fprintf(f, "<method %s>",
|
||||
AS_BOUND_METHOD(printable)->method ? (
|
||||
AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_CLOSURE ? ((KrkClosure*)AS_BOUND_METHOD(printable)->method)->function->name->chars :
|
||||
(AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_NATIVE ? ((KrkNative*)AS_BOUND_METHOD(printable)->method)->name : "(unknown)")) : "(corrupt bound method)"); break;
|
||||
default: fprintf(f, "<%s>", krk_typeName(printable)); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When tracing is enabled, we will present the elements on the stack with
|
||||
* a safe printer; the format of values printed by krk_printValueSafe will
|
||||
@ -90,20 +193,39 @@ static inline const char * opcodeClean(const char * opc) {
|
||||
return &opc[3];
|
||||
}
|
||||
|
||||
static void _overlong_jump(KrkCodeObject * func, size_t offset, size_t operand) {
|
||||
for (size_t i = 0; i < func->overlongJumpsCount; ++i) {
|
||||
if (func->overlongJumps[i].instructionOffset == offset) {
|
||||
operand |= (int)func->overlongJumps[i].intendedTarget << 16;
|
||||
size_t target = offset + 2 + operand;
|
||||
if (func->overlongJumps[i].originalOpcode == OP_LOOP ||
|
||||
func->overlongJumps[i].originalOpcode == OP_LOOP_ITER) {
|
||||
target = offset + 2 - operand;
|
||||
}
|
||||
krk_tableSet(AS_DICT(func->jumpTargets), INTEGER_VAL(target), BOOLEAN_VAL(1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int isJumpTarget(KrkCodeObject * func, size_t startPoint) {
|
||||
KrkChunk * chunk = &func->chunk;
|
||||
size_t offset = 0;
|
||||
|
||||
if (IS_NONE(func->jumpTargets)) {
|
||||
func->jumpTargets = krk_dict_of(0,NULL,0);
|
||||
#define SIMPLE(opc) case opc: size = 1; break;
|
||||
#define CONSTANT(opc,more) case opc: { size_t constant __attribute__((unused)) = chunk->code[offset + 1]; size = 2; more; break; } \
|
||||
case opc ## _LONG: { size_t constant __attribute__((unused)) = (chunk->code[offset + 1] << 16) | \
|
||||
#define CONSTANT(opc,more) case opc: { size_t constant _unused = chunk->code[offset + 1]; size = 2; more; break; } \
|
||||
case opc ## _LONG: { size_t constant _unused = (chunk->code[offset + 1] << 16) | \
|
||||
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
|
||||
#define OPERANDB(opc,more) case opc: { size = 2; more; break; }
|
||||
#define OPERAND(opc,more) OPERANDB(opc,more) \
|
||||
case opc ## _LONG: { size = 4; more; break; }
|
||||
#define JUMP(opc,sign) case opc: { uint16_t jump = (chunk->code[offset + 1] << 8) | (chunk->code[offset + 2]); \
|
||||
if ((size_t)(offset + 3 sign jump) == startPoint) return 1; \
|
||||
krk_tableSet(AS_DICT(func->jumpTargets), INTEGER_VAL((size_t)(offset + 3 sign jump)), BOOLEAN_VAL(1)); \
|
||||
size = 3; break; }
|
||||
#define COMPLICATED(opc,more) case opc: size = 1; more; break;
|
||||
#define OVERLONG_JUMP_MORE size += 2; _overlong_jump(func, offset+1, (chunk->code[offset + 1] << 8) | (chunk->code[offset + 2]))
|
||||
#define CLOSURE_MORE \
|
||||
KrkCodeObject * function = AS_codeobject(chunk->constants.values[constant]); \
|
||||
for (size_t j = 0; j < function->upvalueCount; ++j) { \
|
||||
@ -125,16 +247,23 @@ static int isJumpTarget(KrkCodeObject * func, size_t startPoint) {
|
||||
}
|
||||
offset += size;
|
||||
}
|
||||
return 0;
|
||||
#undef SIMPLE
|
||||
#undef OPERANDB
|
||||
#undef OPERAND
|
||||
#undef CONSTANT
|
||||
#undef JUMP
|
||||
#undef COMPLICATED
|
||||
#undef OVERLONG_JUMP_MORE
|
||||
#undef CLOSURE_MORE
|
||||
#undef LOCAL_MORE
|
||||
#undef EXPAND_ARGS_MORE
|
||||
#undef FORMAT_VALUE_MORE
|
||||
}
|
||||
|
||||
if (!IS_dict(func->jumpTargets)) return 0;
|
||||
KrkValue garbage;
|
||||
if (krk_tableGet(AS_DICT(func->jumpTargets), INTEGER_VAL(startPoint), &garbage)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OPARGS FILE * f, const char * fullName, size_t * size, size_t * offset, KrkCodeObject * func, KrkChunk * chunk
|
||||
@ -174,6 +303,41 @@ static void _jump(OPARGS, int sign) {
|
||||
*size = 3;
|
||||
}
|
||||
|
||||
static void _complicated(OPARGS, void (*more)(OPARGS)) {
|
||||
_print_opcode(OPARG_VALS);
|
||||
if (more) more(OPARG_VALS);
|
||||
else *size = 1;
|
||||
}
|
||||
|
||||
#define SIMPLE(opc)
|
||||
#define JUMP(opc,sign) case opc: fprintf(f, "(%s, to %zu)", opcodeClean(#opc), *offset + 3 sign current_jump); return;
|
||||
#define OPERAND(opc,more)
|
||||
#define CONSTANT(opc,more)
|
||||
#define COMPLICATED(opc,more)
|
||||
static void _overlong_jump_more(OPARGS) {
|
||||
size_t current_jump = (chunk->code[*offset + 1] << 8) | (chunk->code[*offset + 2]);
|
||||
*size = 3;
|
||||
|
||||
/* Now look it up */
|
||||
for (size_t i = 0; i < func->overlongJumpsCount; ++i) {
|
||||
if (*offset + 1 == (size_t)func->overlongJumps[i].instructionOffset) {
|
||||
current_jump |= ((size_t)func->overlongJumps[i].intendedTarget << 16);
|
||||
switch (func->overlongJumps[i].originalOpcode) {
|
||||
#include "opcodes.h"
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f,"(invalid destination)");
|
||||
}
|
||||
#undef SIMPLE
|
||||
#undef OPERAND
|
||||
#undef CONSTANT
|
||||
#undef JUMP
|
||||
#undef COMPLICATED
|
||||
|
||||
|
||||
#undef NOOP
|
||||
#define NOOP (NULL)
|
||||
#define SIMPLE(opc) case opc: _simple(f,#opc,&size,&offset,func,chunk); break;
|
||||
@ -182,6 +346,9 @@ static void _jump(OPARGS, int sign) {
|
||||
#define OPERAND(opc,more) case opc: _operand(f,#opc,&size,&offset,func,chunk,0,more); break; \
|
||||
case opc ## _LONG: _operand(f,#opc "_LONG",&size,&offset,func,chunk,1,more); break;
|
||||
#define JUMP(opc,sign) case opc: _jump(f,#opc,&size,&offset,func,chunk,sign 1); break;
|
||||
#define COMPLICATED(opc,more) case opc: _complicated(f,#opc,&size,&offset,func,chunk,more); break;
|
||||
|
||||
#define OVERLONG_JUMP_MORE _overlong_jump_more
|
||||
|
||||
#define CLOSURE_MORE _closure_more
|
||||
|
||||
@ -202,6 +369,8 @@ static void _closure_more(OPARGS, size_t constant) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (isLocal & 4) {
|
||||
fprintf(f, "classcell");
|
||||
} else { fprintf(f, "upvalue<%d>", index); }
|
||||
if (j + 1 != function->upvalueCount) fprintf(f, ", ");
|
||||
}
|
||||
@ -289,34 +458,14 @@ size_t krk_disassembleInstruction(FILE * f, KrkCodeObject * func, size_t offset)
|
||||
#undef OPERAND
|
||||
#undef CONSTANT
|
||||
#undef JUMP
|
||||
#undef COMPLICATED
|
||||
#undef OVERLONG_JUMP_MORE
|
||||
#undef CLOSURE_MORE
|
||||
#undef LOCAL_MORE
|
||||
#undef EXPAND_ARGS_MORE
|
||||
#undef FORMAT_VALUE_MORE
|
||||
#undef NOOP
|
||||
|
||||
struct BreakpointEntry {
|
||||
KrkCodeObject * inFunction;
|
||||
size_t offset;
|
||||
int flags;
|
||||
uint8_t originalOpcode;
|
||||
};
|
||||
|
||||
#define MAX_BREAKPOINTS 32
|
||||
struct DebuggerState {
|
||||
int breakpointsCount;
|
||||
KrkDebugCallback debuggerHook;
|
||||
|
||||
/* XXX This was previously thread-local; it probably should still be
|
||||
* specific to an individual thread... but we don't really do
|
||||
* much thread debugging, so... */
|
||||
int repeatStack_top;
|
||||
int repeatStack_bottom;
|
||||
int thisWasForced;
|
||||
|
||||
struct BreakpointEntry breakpoints[MAX_BREAKPOINTS];
|
||||
};
|
||||
|
||||
int krk_debug_addBreakpointCodeOffset(KrkCodeObject * target, size_t offset, int flags) {
|
||||
int index = vm.dbgState->breakpointsCount;
|
||||
if (vm.dbgState->breakpointsCount == MAX_BREAKPOINTS) {
|
||||
@ -389,12 +538,6 @@ int krk_debug_enableBreakpoint(int breakIndex) {
|
||||
vm.dbgState->breakpoints[breakIndex].inFunction->chunk.code[vm.dbgState->breakpoints[breakIndex].offset] = OP_BREAKPOINT;
|
||||
return 0;
|
||||
}
|
||||
KRK_Function(enablebreakpoint) {
|
||||
CHECK_ARG(0,int,krk_integer_type,breakIndex);
|
||||
if (krk_debug_enableBreakpoint(breakIndex))
|
||||
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
int krk_debug_disableBreakpoint(int breakIndex) {
|
||||
if (breakIndex < 0 || breakIndex >= vm.dbgState->breakpointsCount || vm.dbgState->breakpoints[breakIndex].inFunction == NULL)
|
||||
@ -406,12 +549,6 @@ int krk_debug_disableBreakpoint(int breakIndex) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
KRK_Function(disablebreakpoint) {
|
||||
CHECK_ARG(0,int,krk_integer_type,breakIndex);
|
||||
if (krk_debug_disableBreakpoint(breakIndex))
|
||||
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
int krk_debug_removeBreakpoint(int breakIndex) {
|
||||
if (breakIndex < 0 || breakIndex >= vm.dbgState->breakpointsCount || vm.dbgState->breakpoints[breakIndex].inFunction == NULL)
|
||||
@ -423,61 +560,6 @@ int krk_debug_removeBreakpoint(int breakIndex) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
KRK_Function(delbreakpoint) {
|
||||
CHECK_ARG(0,int,krk_integer_type,breakIndex);
|
||||
if (krk_debug_removeBreakpoint(breakIndex))
|
||||
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Function(addbreakpoint) {
|
||||
FUNCTION_TAKES_EXACTLY(2);
|
||||
CHECK_ARG(1,int,krk_integer_type,lineNo);
|
||||
|
||||
int flags = KRK_BREAKPOINT_NORMAL;
|
||||
|
||||
if (hasKw) {
|
||||
KrkValue flagsValue = NONE_VAL();
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("flags")), &flagsValue)) {
|
||||
if (!IS_INTEGER(flagsValue))
|
||||
return TYPE_ERROR(int,flagsValue);
|
||||
flags = AS_INTEGER(flagsValue);
|
||||
}
|
||||
}
|
||||
|
||||
int result;
|
||||
if (IS_STRING(argv[0])) {
|
||||
result = krk_debug_addBreakpointFileLine(AS_STRING(argv[0]), lineNo, flags);
|
||||
} else {
|
||||
KrkCodeObject * target = NULL;
|
||||
if (IS_CLOSURE(argv[0])) {
|
||||
target = AS_CLOSURE(argv[0])->function;
|
||||
} else if (IS_BOUND_METHOD(argv[0]) && IS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(argv[0])->method))) {
|
||||
target = AS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(argv[0])->method))->function;
|
||||
} else if (IS_codeobject(argv[0])) {
|
||||
target = AS_codeobject(argv[0]);
|
||||
} else {
|
||||
return TYPE_ERROR(function or method or filename,argv[0]);
|
||||
}
|
||||
/* Figure out what instruction this should be on */
|
||||
size_t last = 0;
|
||||
for (size_t i = 0; i < target->chunk.linesCount; ++i) {
|
||||
if (target->chunk.lines[i].line > (size_t)lineNo) break;
|
||||
if (target->chunk.lines[i].line == (size_t)lineNo) {
|
||||
last = target->chunk.lines[i].startOffset;
|
||||
break;
|
||||
}
|
||||
last = target->chunk.lines[i].startOffset;
|
||||
}
|
||||
result = krk_debug_addBreakpointCodeOffset(target,last,flags);
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
return krk_runtimeError(vm.exceptions->baseException, "Could not add breakpoint.");
|
||||
|
||||
return INTEGER_VAL(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Begin debugger utility functions.
|
||||
*
|
||||
@ -614,237 +696,46 @@ int krk_debugBreakpointHandler(void) {
|
||||
return krk_debuggerHook(frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* dis.dis(object)
|
||||
*/
|
||||
KRK_Function(dis) {
|
||||
FUNCTION_TAKES_EXACTLY(1);
|
||||
|
||||
if (IS_CLOSURE(argv[0])) {
|
||||
KrkCodeObject * func = AS_CLOSURE(argv[0])->function;
|
||||
krk_disassembleCodeObject(stdout, func, func->name ? func->name->chars : "<unnamed>");
|
||||
} else if (IS_codeobject(argv[0])) {
|
||||
krk_disassembleCodeObject(stdout, AS_codeobject(argv[0]), AS_codeobject(argv[0])->name ? AS_codeobject(argv[0])->name->chars : "<unnamed>");
|
||||
} else if (IS_BOUND_METHOD(argv[0])) {
|
||||
if (AS_BOUND_METHOD(argv[0])->method->type == KRK_OBJ_CLOSURE) {
|
||||
KrkCodeObject * func = ((KrkClosure*)AS_BOUND_METHOD(argv[0])->method)->function;
|
||||
const char * methodName = func->name ? func->name->chars : "<unnamed>";
|
||||
const char * typeName = IS_CLASS(AS_BOUND_METHOD(argv[0])->receiver) ? AS_CLASS(AS_BOUND_METHOD(argv[0])->receiver)->name->chars : krk_typeName(AS_BOUND_METHOD(argv[0])->receiver);
|
||||
size_t allocSize = strlen(methodName) + strlen(typeName) + 2;
|
||||
char * tmp = malloc(allocSize);
|
||||
snprintf(tmp, allocSize, "%s.%s", typeName, methodName);
|
||||
krk_disassembleCodeObject(stdout, func, tmp);
|
||||
free(tmp);
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%T'", AS_BOUND_METHOD(argv[0])->receiver);
|
||||
}
|
||||
} else if (IS_CLASS(argv[0])) {
|
||||
KrkValue code;
|
||||
if (krk_tableGet(&AS_CLASS(argv[0])->methods, OBJECT_VAL(S("__func__")), &code) && IS_CLOSURE(code)) {
|
||||
KrkCodeObject * func = AS_CLOSURE(code)->function;
|
||||
krk_disassembleCodeObject(stdout, func, AS_CLASS(argv[0])->name->chars);
|
||||
}
|
||||
/* TODO Methods! */
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%T'", argv[0]);
|
||||
}
|
||||
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Function(build) {
|
||||
FUNCTION_TAKES_AT_LEAST(1);
|
||||
FUNCTION_TAKES_AT_MOST(2);
|
||||
CHECK_ARG(0,str,KrkString*,code);
|
||||
char * fileName = "<source>";
|
||||
if (argc > 1) {
|
||||
CHECK_ARG(1,str,KrkString*,filename);
|
||||
fileName = filename->chars;
|
||||
}
|
||||
|
||||
/* Unset module */
|
||||
krk_push(OBJECT_VAL(krk_currentThread.module));
|
||||
KrkInstance * module = krk_currentThread.module;
|
||||
krk_currentThread.module = NULL;
|
||||
KrkCodeObject * c = krk_compile(code->chars,fileName);
|
||||
krk_currentThread.module = module;
|
||||
krk_pop();
|
||||
if (c) return OBJECT_VAL(c);
|
||||
else return NONE_VAL();
|
||||
}
|
||||
|
||||
#define NOOP (void)0
|
||||
#define SIMPLE(opc) case opc: size = 1; break;
|
||||
#define CONSTANT(opc,more) case opc: { constant = chunk->code[offset + 1]; size = 2; more; break; } \
|
||||
case opc ## _LONG: { constant = (chunk->code[offset + 1] << 16) | \
|
||||
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
|
||||
#define OPERAND(opc,more) case opc: { operand = chunk->code[offset + 1]; size = 2; more; break; } \
|
||||
case opc ## _LONG: { operand = (chunk->code[offset + 1] << 16) | \
|
||||
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
|
||||
#define JUMP(opc,sign) case opc: { jump = 0 sign ((chunk->code[offset + 1] << 8) | (chunk->code[offset + 2])); \
|
||||
size = 3; break; }
|
||||
#define CLOSURE_MORE \
|
||||
KrkCodeObject * function = AS_codeobject(chunk->constants.values[constant]); \
|
||||
size_t baseOffset = offset; \
|
||||
for (size_t j = 0; j < function->upvalueCount; ++j) { \
|
||||
int isLocal = chunk->code[baseOffset++ + size]; \
|
||||
baseOffset++; \
|
||||
if (isLocal & 2) { \
|
||||
baseOffset += 2; \
|
||||
} \
|
||||
} \
|
||||
size += baseOffset - offset;
|
||||
#define EXPAND_ARGS_MORE
|
||||
#define FORMAT_VALUE_MORE
|
||||
#define LOCAL_MORE local = operand;
|
||||
static KrkValue _examineInternal(KrkCodeObject* func) {
|
||||
KrkValue output = krk_list_of(0,NULL,0);
|
||||
krk_push(output);
|
||||
|
||||
KrkChunk * chunk = &func->chunk;
|
||||
size_t offset = 0;
|
||||
while (offset < chunk->count) {
|
||||
uint8_t opcode = chunk->code[offset];
|
||||
size_t size = 0;
|
||||
ssize_t constant = -1;
|
||||
ssize_t jump = 0;
|
||||
ssize_t operand = -1;
|
||||
ssize_t local = -1;
|
||||
switch (opcode) {
|
||||
#include "opcodes.h"
|
||||
}
|
||||
|
||||
KrkTuple * newTuple = krk_newTuple(3);
|
||||
krk_push(OBJECT_VAL(newTuple));
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(opcode);
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(size);
|
||||
if (constant != -1) {
|
||||
newTuple->values.values[newTuple->values.count++] = chunk->constants.values[constant];
|
||||
} else if (jump != 0) {
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(jump);
|
||||
} else if (local != -1) {
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand); /* Just in case */
|
||||
for (size_t i = 0; i < func->localNameCount; ++i) {
|
||||
if (func->localNames[i].id == (size_t)local && func->localNames[i].birthday <= offset && func->localNames[i].deathday >= offset) {
|
||||
newTuple->values.values[newTuple->values.count-1] = OBJECT_VAL(func->localNames[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (operand != -1) {
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand);
|
||||
} else {
|
||||
newTuple->values.values[newTuple->values.count++] = NONE_VAL();
|
||||
}
|
||||
krk_writeValueArray(AS_LIST(output), krk_peek(0));
|
||||
krk_pop();
|
||||
|
||||
if (size == 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
KRK_Function(examine) {
|
||||
FUNCTION_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(0,codeobject,KrkCodeObject*,func);
|
||||
return _examineInternal(func);
|
||||
}
|
||||
|
||||
#undef SIMPLE
|
||||
#undef OPERANDB
|
||||
#undef OPERAND
|
||||
#undef CONSTANT
|
||||
#undef JUMP
|
||||
#undef CLOSURE_MORE
|
||||
#undef LOCAL_MORE
|
||||
#undef EXPAND_ARGS_MORE
|
||||
#undef FORMAT_VALUE_MORE
|
||||
|
||||
void krk_module_init_dis(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_attachNamedObject(&vm.modules, "dis", (KrkObj*)module);
|
||||
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("dis"));
|
||||
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
|
||||
|
||||
void krk_debug_init(void) {
|
||||
vm.dbgState = calloc(1, sizeof(struct DebuggerState));
|
||||
vm.dbgState->repeatStack_top = -1;
|
||||
vm.dbgState->repeatStack_bottom = -1;
|
||||
}
|
||||
|
||||
KRK_DOC(module,
|
||||
"@brief Provides tools for disassembling bytecode.\n\n"
|
||||
"### Code Disassembly in Kuroko\n\n"
|
||||
"The @c dis module contains functions for dealing with _code objects_ which "
|
||||
"represent the compiled bytecode of a Kuroko function. The bytecode compilation "
|
||||
"process is entirely static and bytecode analysis can be performed without calling "
|
||||
"into the VM to run dynamic code.\n\n"
|
||||
"### Debugger Breakpoints\n\n"
|
||||
"Kuroko interpreters can provide a debugger hook through the C API's "
|
||||
"@ref krk_debug_registerCallback() function. Breakpoints can be managed both "
|
||||
"from the C API and from this module's @ref addbreakpoint, @ref delbreakpoint, "
|
||||
"@ref enablebreakpoint, and @ref disablebreakpoint methods."
|
||||
);
|
||||
void krk_debug_addExpression(KrkCodeObject * codeobject, uint8_t start, uint8_t midStart, uint8_t midEnd, uint8_t end) {
|
||||
/* Traceback entries point to the last byte of an opcode, due to the way instruction fetch
|
||||
* advances the instruction pointer past all of the constituent operands of an opcode; as
|
||||
* such, our map is based on these last bytes and we need to look at the byte preceding
|
||||
* the current count when adding new entries. */
|
||||
size_t offset = codeobject->chunk.count - 1;
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, dis),
|
||||
"@brief Disassemble an object.\n"
|
||||
"@arguments obj\n\n"
|
||||
"Dumps a disassembly of the bytecode in the code object associated with @p obj. "
|
||||
"If @p obj can not be disassembled, a @ref TypeError is raised.");
|
||||
/* We can feasibly support offsets larger than UINT32_MAX on 64-bit platforms, though this
|
||||
* should never really happen. Just in case, avoid messing up our table with bad values. */
|
||||
if (offset > UINT32_MAX) return;
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, build),
|
||||
"@brief Compile a string to a code object.\n"
|
||||
"@arguments code\n\n"
|
||||
"Compiles the string @p code and returns a code object. If a syntax "
|
||||
"error is encountered, it will be raised.");
|
||||
if (codeobject->expressionsCapacity < codeobject->expressionsCount + 1) {
|
||||
size_t old = codeobject->expressionsCapacity;
|
||||
codeobject->expressionsCapacity = KRK_GROW_CAPACITY(old);
|
||||
codeobject->expressions = KRK_GROW_ARRAY(KrkExpressionsMap, codeobject->expressions, old, codeobject->expressionsCapacity);
|
||||
}
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, examine),
|
||||
"@brief Convert a code object to a list of instructions.\n"
|
||||
"@arguments func\n\n"
|
||||
"Examines the code object @p func and returns a list representation of its instructions. "
|
||||
"Each instruction entry is a tuple of the opcode, total instruction size in bytes, and "
|
||||
"the operand of the argument, either as an integer for jump offsets, the actual value for "
|
||||
"constant operands, or the name of a local or global variable if available.");
|
||||
codeobject->expressions[codeobject->expressionsCount] = (KrkExpressionsMap){offset,start,midStart,midEnd,end};
|
||||
codeobject->expressionsCount++;
|
||||
}
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, addbreakpoint),
|
||||
"@brief Attach a breakpoint to a code object.\n"
|
||||
"@arguments func, line\n\n"
|
||||
"@p func may be a filename string, or a function, method, or code object. Returns "
|
||||
"the new breakpoint index, or raises @ref Exception if a breakpoint code not be added.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, delbreakpoint),
|
||||
"@brief Delete a breakpoint.\n"
|
||||
"@arguments handle\n\n"
|
||||
"Delete the breakpoint specified by @p handle, disabling it if it was enabled. "
|
||||
"May raise @ref IndexError if @p handle is not a valid breakpoint handle.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, enablebreakpoint),
|
||||
"@brief Enable a breakpoint.\n"
|
||||
"@arguments handle\n\n"
|
||||
"Enable the breakpoint specified by @p handle. May raise @ref IndexError if "
|
||||
"@p handle is not a valid breakpoint handle.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, disablebreakpoint),
|
||||
"@brief Disable a breakpoint.\n"
|
||||
"@arguments handle\n\n"
|
||||
"Disable the breakpoint specified by @p handle. May raise @ref IndexError if "
|
||||
"@p handle is not a valid breakpoint handle.");
|
||||
|
||||
krk_attachNamedValue(&module->fields, "BREAKPOINT_ONCE", INTEGER_VAL(KRK_BREAKPOINT_ONCE));
|
||||
krk_attachNamedValue(&module->fields, "BREAKPOINT_REPEAT", INTEGER_VAL(KRK_BREAKPOINT_REPEAT));
|
||||
|
||||
#define OPCODE(opc) krk_attachNamedValue(&module->fields, #opc, INTEGER_VAL(opc));
|
||||
#define SIMPLE(opc) OPCODE(opc)
|
||||
#define CONSTANT(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
|
||||
#define OPERAND(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
|
||||
#define JUMP(opc,sign) OPCODE(opc)
|
||||
#include "opcodes.h"
|
||||
#undef SIMPLE
|
||||
#undef OPERANDB
|
||||
#undef OPERAND
|
||||
#undef CONSTANT
|
||||
#undef JUMP
|
||||
int krk_debug_expressionUnderline(const KrkCodeObject* codeobject, uint8_t* start, uint8_t* midStart, uint8_t* midEnd, uint8_t* end, size_t instruction) {
|
||||
/* We could do binary search here, but as we only print these when an exception 'escapes',
|
||||
* it's not really worth the optimization over a linear search per line in the traceback. */
|
||||
for (size_t i = 0; i < codeobject->expressionsCount; ++i) {
|
||||
if (codeobject->expressions[i].bytecodeOffset == instruction) {
|
||||
*start = codeobject->expressions[i].start;
|
||||
*midStart = codeobject->expressions[i].midStart;
|
||||
*midEnd = codeobject->expressions[i].midEnd;
|
||||
*end = codeobject->expressions[i].end;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -45,7 +45,7 @@ KRK_Method(BaseException,__init__) {
|
||||
}
|
||||
krk_attachNamedValue(&self->fields, "__cause__", NONE_VAL());
|
||||
krk_attachNamedValue(&self->fields, "__context__", NONE_VAL());
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -273,7 +273,7 @@ static void dumpInnerException(KrkValue exception, int depth) {
|
||||
lineNo,
|
||||
(function->name ? function->name->chars : "(unnamed)"));
|
||||
|
||||
#ifndef NO_SOURCE_IN_TRACEBACK
|
||||
#ifndef KRK_NO_SOURCE_IN_TRACEBACK
|
||||
/* Try to open the file */
|
||||
if (function->chunk.filename) {
|
||||
FILE * f = fopen(function->chunk.filename->chars, "r");
|
||||
@ -288,12 +288,27 @@ static void dumpInnerException(KrkValue exception, int depth) {
|
||||
}
|
||||
if (line == lineNo) {
|
||||
fprintf(stderr," ");
|
||||
while (c == ' ') c = fgetc(f);
|
||||
unsigned short j = 1;
|
||||
while (c == ' ' || c == '\t') {
|
||||
c = fgetc(f);
|
||||
j++;
|
||||
}
|
||||
do {
|
||||
fputc(c, stderr);
|
||||
c = fgetc(f);
|
||||
} while (!feof(f) && c > 0 && c != '\n');
|
||||
fprintf(stderr, "\n");
|
||||
#ifndef KRK_DISABLE_DEBUG
|
||||
uint8_t start, midStart, midEnd, end;
|
||||
if (krk_debug_expressionUnderline(function, &start, &midStart, &midEnd, &end, instruction)) {
|
||||
fprintf(stderr," ");
|
||||
for (; j < start; ++j) fprintf(stderr," ");
|
||||
for (; j < midStart; ++j) fprintf(stderr,"~");
|
||||
for (; j < midEnd; ++j) fprintf(stderr, "^");
|
||||
for (; j < end; ++j) fprintf(stderr,"~");
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
} while (!feof(f));
|
||||
@ -461,7 +476,7 @@ KrkValue krk_runtimeError(KrkClass * type, const char * fmt, ...) {
|
||||
/* Allocate an exception object of the requested type. */
|
||||
KrkInstance * exceptionObject = krk_newInstance(type);
|
||||
krk_push(OBJECT_VAL(exceptionObject));
|
||||
krk_attachNamedValue(&exceptionObject->fields, "arg", msg == KWARGS_VAL(0) ? finishStringBuilder(&sb) : msg);
|
||||
krk_attachNamedValue(&exceptionObject->fields, "arg", krk_valuesSame(msg,KWARGS_VAL(0)) ? finishStringBuilder(&sb) : msg);
|
||||
krk_attachNamedValue(&exceptionObject->fields, "__cause__", NONE_VAL());
|
||||
krk_attachNamedValue(&exceptionObject->fields, "__context__", NONE_VAL());
|
||||
krk_pop();
|
||||
|
112
src/kuroko.c
112
src/kuroko.c
@ -33,11 +33,10 @@
|
||||
#define PROMPT_MAIN ">>> "
|
||||
#define PROMPT_BLOCK " > "
|
||||
|
||||
#define CALLGRIND_TMP_FILE "/tmp/kuroko.callgrind.tmp"
|
||||
|
||||
static int enableRline = 1;
|
||||
static int exitRepl = 0;
|
||||
static int pasteEnabled = 0;
|
||||
static int noColor = 0;
|
||||
|
||||
KRK_Function(exit) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
@ -128,6 +127,16 @@ KRK_Function(input) {
|
||||
return readLine(prompt, promptwidth, syntax);
|
||||
}
|
||||
|
||||
static void printResult(FILE * file, KrkValue result) {
|
||||
struct StringBuilder sb = {0};
|
||||
if (!krk_pushStringBuilderFormat(&sb, noColor ? " => %R\n" : " \033[1;90m=> %R\033[0m\n", result)) {
|
||||
krk_dumpTraceback();
|
||||
} else {
|
||||
fwrite(sb.bytes,1,sb.length,file);
|
||||
}
|
||||
krk_discardStringBuilder(&sb);
|
||||
}
|
||||
|
||||
#ifndef NO_RLINE
|
||||
/**
|
||||
* Given an object, find a property with the same name as a scanner token.
|
||||
@ -468,9 +477,7 @@ static int debuggerHook(KrkCallFrame * frame) {
|
||||
krk_pop();
|
||||
/* Call the compiled expression with no args. */
|
||||
krk_push(krk_callStack(0));
|
||||
fprintf(stderr, "\033[1;30m=> ");
|
||||
krk_printValue(stderr, krk_peek(0));
|
||||
fprintf(stderr, "\033[0m\n");
|
||||
printResult(stderr, krk_peek(0));
|
||||
krk_pop();
|
||||
}
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
|
||||
@ -744,16 +751,6 @@ static int compileFile(char * argv[], int flags, char * fileName) {
|
||||
return func == NULL;
|
||||
}
|
||||
|
||||
#ifdef BUNDLE_LIBS
|
||||
#define BUNDLED(name) do { \
|
||||
extern KrkValue krk_module_onload_ ## name (); \
|
||||
KrkValue moduleOut = krk_module_onload_ ## name (); \
|
||||
krk_attachNamedValue(&vm.modules, # name, moduleOut); \
|
||||
krk_attachNamedObject(&AS_INSTANCE(moduleOut)->fields, "__name__", (KrkObj*)krk_copyString(#name, sizeof(#name)-1)); \
|
||||
krk_attachNamedValue(&AS_INSTANCE(moduleOut)->fields, "__file__", NONE_VAL()); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
#ifdef _WIN32
|
||||
SetConsoleOutputCP(65001);
|
||||
@ -788,11 +785,6 @@ int main(int argc, char * argv[]) {
|
||||
/* Disassemble instructions as they are executed. */
|
||||
flags |= KRK_THREAD_ENABLE_TRACING;
|
||||
break;
|
||||
case 'T': {
|
||||
flags |= KRK_GLOBAL_CALLGRIND;
|
||||
vm.callgrindFile = fopen(CALLGRIND_TMP_FILE,"w");
|
||||
break;
|
||||
}
|
||||
case 'i':
|
||||
inspectAfter = 1;
|
||||
break;
|
||||
@ -838,7 +830,6 @@ int main(int argc, char * argv[]) {
|
||||
" -r Disable complex line editing in the REPL.\n"
|
||||
" -R depth Set maximum recursion depth.\n"
|
||||
" -t Disassemble instructions as they are exceuted.\n"
|
||||
" -T Write call trace file.\n"
|
||||
" -C file Compile 'file', but do not execute it.\n"
|
||||
" -M Print the default module import paths.\n"
|
||||
" -S Enable single-step debugging.\n"
|
||||
@ -885,20 +876,26 @@ _finishArgs:
|
||||
/* Bind interrupt signal */
|
||||
bindSignalHandlers();
|
||||
|
||||
#ifdef BUNDLE_LIBS
|
||||
/* Add any other modules you want to include that are normally built as shared objects. */
|
||||
BUNDLED(math);
|
||||
BUNDLED(socket);
|
||||
BUNDLED(timeit);
|
||||
#ifdef KRK_BUNDLE_LIBS
|
||||
/* Define KRK_BUNDLE_LIBS like "BUNDLE(os);BUNDLE(math);", etc. */
|
||||
#define BUNDLED(name) do { \
|
||||
extern KrkValue krk_module_onload_ ## name (KrkString*); \
|
||||
KrkValue moduleOut = krk_module_onload_ ## name (NULL); \
|
||||
krk_attachNamedValue(&vm.modules, # name, moduleOut); \
|
||||
krk_attachNamedObject(&AS_INSTANCE(moduleOut)->fields, "__name__", (KrkObj*)krk_copyString(#name, sizeof(#name)-1)); \
|
||||
krk_attachNamedValue(&AS_INSTANCE(moduleOut)->fields, "__file__", NONE_VAL()); \
|
||||
} while (0)
|
||||
KRK_BUNDLE_LIBS
|
||||
#undef BUNDLED
|
||||
#endif
|
||||
|
||||
KrkValue result = INTEGER_VAL(0);
|
||||
|
||||
char * _KUROKOPATH = getenv("KUROKOPATH");
|
||||
char * env_KUROKOPATH = getenv("KUROKOPATH");
|
||||
|
||||
if (_KUROKOPATH) {
|
||||
if (env_KUROKOPATH) {
|
||||
/* Build a path by splitting */
|
||||
krk_push(OBJECT_VAL(krk_copyString(_KUROKOPATH,strlen(_KUROKOPATH))));
|
||||
krk_push(OBJECT_VAL(krk_copyString(env_KUROKOPATH,strlen(env_KUROKOPATH))));
|
||||
krk_push(OBJECT_VAL(S(":")));
|
||||
|
||||
/* Split into list */
|
||||
@ -922,12 +919,16 @@ _finishArgs:
|
||||
krk_pop(); /* list */
|
||||
}
|
||||
|
||||
char * env_NO_COLOR = getenv("NO_COLOR");
|
||||
|
||||
if (env_NO_COLOR && *env_NO_COLOR) noColor = 1;
|
||||
|
||||
/**
|
||||
* Add general builtins that aren't part of the core VM.
|
||||
* This is where we provide @c input in particular.
|
||||
*/
|
||||
KRK_DOC(BIND_FUNC(vm.builtins,input), "@brief Read a line of input.\n"
|
||||
"@arguments [prompt], promptwidth=None, syntax=None\n\n"
|
||||
"@arguments prompt='',promptwidth=0,syntax=None\n\n"
|
||||
"Read a line of input from @c stdin. If the @c rline library is available, "
|
||||
"it will be used to gather input. Input reading stops on end-of file or when "
|
||||
"a read ends with a line feed, which will be removed from the returned string. "
|
||||
@ -941,10 +942,7 @@ _finishArgs:
|
||||
"provide color highlighting of the input line.");
|
||||
|
||||
if (moduleAsMain) {
|
||||
krk_push(OBJECT_VAL(krk_copyString("__main__",8)));
|
||||
int out = !krk_importModule(
|
||||
AS_STRING(AS_LIST(argList)->values[0]),
|
||||
AS_STRING(krk_peek(0)));
|
||||
int out = !krk_importModule(AS_STRING(AS_LIST(argList)->values[0]), S("__main__"));
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
|
||||
krk_dumpTraceback();
|
||||
krk_resetStack();
|
||||
@ -990,12 +988,11 @@ _finishArgs:
|
||||
* This module won't be imported by default, but it's still in
|
||||
* the modules list, so we can look for it there.
|
||||
*/
|
||||
KrkValue systemModule;
|
||||
if (krk_tableGet(&vm.modules, OBJECT_VAL(krk_copyString("kuroko",6)), &systemModule)) {
|
||||
if (vm.system) {
|
||||
KrkValue version, buildenv, builddate;
|
||||
krk_tableGet(&AS_INSTANCE(systemModule)->fields, OBJECT_VAL(krk_copyString("version",7)), &version);
|
||||
krk_tableGet(&AS_INSTANCE(systemModule)->fields, OBJECT_VAL(krk_copyString("buildenv",8)), &buildenv);
|
||||
krk_tableGet(&AS_INSTANCE(systemModule)->fields, OBJECT_VAL(krk_copyString("builddate",9)), &builddate);
|
||||
krk_tableGet_fast(&vm.system->fields, S("version"), &version);
|
||||
krk_tableGet_fast(&vm.system->fields, S("buildenv"), &buildenv);
|
||||
krk_tableGet_fast(&vm.system->fields, S("builddate"), &builddate);
|
||||
|
||||
fprintf(stdout, "Kuroko %s (%s) with %s\n",
|
||||
AS_CSTRING(version), AS_CSTRING(builddate), AS_CSTRING(buildenv));
|
||||
@ -1006,7 +1003,7 @@ _finishArgs:
|
||||
while (!exitRepl) {
|
||||
size_t lineCapacity = 8;
|
||||
size_t lineCount = 0;
|
||||
char ** lines = ALLOCATE(char *, lineCapacity);
|
||||
char ** lines = KRK_ALLOCATE(char *, lineCapacity);
|
||||
size_t totalData = 0;
|
||||
int valid = 1;
|
||||
char * allData = NULL;
|
||||
@ -1092,8 +1089,8 @@ _finishArgs:
|
||||
if (lineCapacity < lineCount + 1) {
|
||||
/* If we need more space, grow as needed... */
|
||||
size_t old = lineCapacity;
|
||||
lineCapacity = GROW_CAPACITY(old);
|
||||
lines = GROW_ARRAY(char *,lines,old,lineCapacity);
|
||||
lineCapacity = KRK_GROW_CAPACITY(old);
|
||||
lines = KRK_GROW_ARRAY(char *,lines,old,lineCapacity);
|
||||
}
|
||||
|
||||
int i = lineCount++;
|
||||
@ -1162,26 +1159,13 @@ _finishArgs:
|
||||
#endif
|
||||
free(lines[i]);
|
||||
}
|
||||
FREE_ARRAY(char *, lines, lineCapacity);
|
||||
KRK_FREE_ARRAY(char *, lines, lineCapacity);
|
||||
|
||||
if (valid) {
|
||||
KrkValue result = krk_interpret(allData, "<stdin>");
|
||||
if (!IS_NONE(result)) {
|
||||
krk_attachNamedValue(&vm.builtins->fields, "_", result);
|
||||
KrkClass * type = krk_getType(result);
|
||||
const char * formatStr = " \033[1;90m=> %s\033[0m\n";
|
||||
if (type->_reprer) {
|
||||
krk_push(result);
|
||||
result = krk_callDirect(type->_reprer, 1);
|
||||
} else if (type->_tostr) {
|
||||
krk_push(result);
|
||||
result = krk_callDirect(type->_tostr, 1);
|
||||
}
|
||||
if (!IS_STRING(result)) {
|
||||
fprintf(stdout, " \033[1;91m=> Unable to produce representation for value.\033[0m\n");
|
||||
} else {
|
||||
fprintf(stdout, formatStr, AS_CSTRING(result));
|
||||
}
|
||||
printResult(stdout, result);
|
||||
}
|
||||
krk_resetStack();
|
||||
free(allData);
|
||||
@ -1191,20 +1175,6 @@ _finishArgs:
|
||||
}
|
||||
}
|
||||
|
||||
if (vm.globalFlags & KRK_GLOBAL_CALLGRIND) {
|
||||
fclose(vm.callgrindFile);
|
||||
vm.globalFlags &= ~(KRK_GLOBAL_CALLGRIND);
|
||||
|
||||
krk_resetStack();
|
||||
krk_startModule("<callgrind>");
|
||||
krk_attachNamedObject(&krk_currentThread.module->fields, "filename", (KrkObj*)S(CALLGRIND_TMP_FILE));
|
||||
krk_interpret(
|
||||
"from callgrind import processFile\n"
|
||||
"import kuroko\n"
|
||||
"import os\n"
|
||||
"processFile(filename, os.getpid(), ' '.join(kuroko.argv))","<callgrind>");
|
||||
}
|
||||
|
||||
krk_freeVM();
|
||||
|
||||
if (IS_INTEGER(result)) return AS_INTEGER(result);
|
||||
|
@ -14,5 +14,5 @@
|
||||
* @param fileName Path name of the source file or a representative string like "<stdin>"
|
||||
* @return The code object resulting from the compilation, or NULL if compilation failed.
|
||||
*/
|
||||
extern KrkCodeObject * krk_compile(const char * src, char * fileName);
|
||||
extern KrkCodeObject * krk_compile(const char * src, const char * fileName);
|
||||
|
||||
|
@ -206,6 +206,11 @@ extern int krk_debug_examineBreakpoint(int breakIndex, KrkCodeObject ** funcOut,
|
||||
*/
|
||||
extern void krk_debug_dumpStack(FILE * f, KrkCallFrame * frame);
|
||||
|
||||
/**
|
||||
* @brief Initialize debugger state. Call exactly once per VM.
|
||||
*/
|
||||
extern void krk_debug_init(void);
|
||||
|
||||
/**
|
||||
* @def KRK_BREAKPOINT_NORMAL
|
||||
*
|
||||
@ -233,4 +238,55 @@ extern void krk_debug_dumpStack(FILE * f, KrkCallFrame * frame);
|
||||
#define KRK_DEBUGGER_RAISE 3
|
||||
#define KRK_DEBUGGER_QUIT 4
|
||||
|
||||
/**
|
||||
* @brief Add an expression mapping to the bytecode chunk.
|
||||
* @memberof KrkCodeObject
|
||||
*
|
||||
* Associates a span of columns representing an expression with the
|
||||
* current opcode offset. Used to supply debug information displayed
|
||||
* in tracebacks with tildes and carets.
|
||||
*
|
||||
* @param codeobject Codeobject containing the instruction.
|
||||
* @param start First column, 1-indexed, of tildes, left side of expression.
|
||||
* @param midStart First column, 1-indexed, of carets, main token of expression.
|
||||
* @param midEnd Last column, 1-indexed, of carets, main token of expression.
|
||||
* @param end Last column, 1-indexed, of tildes, right side of expression.
|
||||
*/
|
||||
extern void krk_debug_addExpression(KrkCodeObject * codeobject, uint8_t start, uint8_t midStart, uint8_t midEnd, uint8_t end);
|
||||
|
||||
/**
|
||||
* @brief Extract expression mapping from chunk.
|
||||
* @memberof KrkCodeObject
|
||||
*
|
||||
* Searches the debug information for the requested instruction to find
|
||||
* an expression mapping and extracts the column values for underlining.
|
||||
*
|
||||
* @param codeobject Codeobject containing the instruction.
|
||||
* @param start First column, 1-indexed, of tildes, left side of expression.
|
||||
* @param midStart First column, 1-indexed, of carets, main token of expression.
|
||||
* @param midEnd Last column, 1-indexed, of carets, main token of expression.
|
||||
* @param end Last column, 1-indexed, of tildes, right side of expression.
|
||||
* @param instruction Offset of the last byte of an opcode, as is stored in a traceback entry.
|
||||
* @returns Non-zero if a mapping was found.
|
||||
*/
|
||||
extern int krk_debug_expressionUnderline(const KrkCodeObject * codeobject, uint8_t * start, uint8_t * midStart, uint8_t * endStart, uint8_t * end, size_t instruction);
|
||||
|
||||
/**
|
||||
* @brief Print a value without calling the VM.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Print a string representation of 'value' to the stream 'f',
|
||||
* avoiding calls to managed code by using simplified representations
|
||||
* where necessary. This is intended for use in debugging code, such
|
||||
* as during disassembly, or when printing values in an untrusted context.
|
||||
*
|
||||
* @note This function will truncate long strings and print them in a form
|
||||
* closer to the 'repr()' representation, with escaped bytes, rather
|
||||
* than directly printing them to the stream.
|
||||
*
|
||||
* @param f Stream to write to.
|
||||
* @param value Value to display.
|
||||
*/
|
||||
extern void krk_printValueSafe(FILE * f, KrkValue value);
|
||||
|
||||
#endif
|
||||
|
@ -11,24 +11,37 @@
|
||||
typedef int64_t krk_integer_type;
|
||||
|
||||
#ifndef _WIN32
|
||||
# define PATH_SEP "/"
|
||||
# ifndef STATIC_ONLY
|
||||
# define KRK_PATH_SEP "/"
|
||||
# ifndef KRK_STATIC_ONLY
|
||||
# include <dlfcn.h>
|
||||
# define dlRefType void *
|
||||
# define dlSymType void *
|
||||
# define dlOpen(fileName) dlopen(fileName, RTLD_NOW)
|
||||
# define dlSym(dlRef, handlerName) dlsym(dlRef,handlerName)
|
||||
# define dlClose(dlRef) dlclose(dlRef)
|
||||
# define krk_dlRefType void *
|
||||
# define krk_dlSymType void *
|
||||
# define krk_dlOpen(fileName) dlopen(fileName, RTLD_NOW)
|
||||
# define krk_dlSym(dlRef, handlerName) dlsym(dlRef,handlerName)
|
||||
# define krk_dlClose(dlRef) dlclose(dlRef)
|
||||
# endif
|
||||
#else
|
||||
# include <windows.h>
|
||||
# define PATH_SEP "\\"
|
||||
# ifndef STATIC_ONLY
|
||||
# define dlRefType HINSTANCE
|
||||
# define dlSymType FARPROC
|
||||
# define dlOpen(fileName) LoadLibraryA(fileName)
|
||||
# define dlSym(dlRef, handlerName) GetProcAddress(dlRef, handlerName)
|
||||
# define dlClose(dlRef)
|
||||
# define KRK_PATH_SEP "\\"
|
||||
# ifndef KRK_STATIC_ONLY
|
||||
# define krk_dlRefType HINSTANCE
|
||||
# define krk_dlSymType FARPROC
|
||||
# define krk_dlOpen(fileName) LoadLibraryA(fileName)
|
||||
# define krk_dlSym(dlRef, handlerName) GetProcAddress(dlRef, handlerName)
|
||||
# define krk_dlClose(dlRef)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define KRK_NO_DOCUMENTATION 1
|
||||
#define KRK_NO_GC_TRACING 1
|
||||
typedef intptr_t ssize_t;
|
||||
#pragma warning(disable : 4146) /* unary minus on unsigned */
|
||||
#pragma warning(disable : 4996) /* sterror */
|
||||
#pragma warning(disable : 4267) /* conversions to smaller types... */
|
||||
#pragma warning(disable : 4244) /* conversions to smaller types... */
|
||||
#include <math.h>
|
||||
#define __builtin_floor floor
|
||||
#define __builtin_unreachable abort
|
||||
#define __builtin_expect(cond,expected) (cond)
|
||||
#endif
|
||||
|
@ -7,13 +7,10 @@
|
||||
#include "object.h"
|
||||
#include "table.h"
|
||||
|
||||
#define GROW_CAPACITY(c) ((c) < 8 ? 8 : (c) * 2)
|
||||
#define GROW_ARRAY(t,p,o,n) (t*)krk_reallocate(p,sizeof(t)*o,sizeof(t)*n)
|
||||
|
||||
#define FREE_ARRAY(t,a,c) krk_reallocate(a,sizeof(t) * c, 0)
|
||||
#define FREE(t,p) krk_reallocate(p,sizeof(t),0)
|
||||
|
||||
#define ALLOCATE(type, count) (type*)krk_reallocate(NULL,0,sizeof(type)*(count))
|
||||
#define KRK_GROW_CAPACITY(c) ((c) < 8 ? 8 : (c) * 2)
|
||||
#define KRK_GROW_ARRAY(t,p,o,n) (t*)krk_reallocate(p,sizeof(t)*o,sizeof(t)*n)
|
||||
#define KRK_FREE_ARRAY(t,a,c) krk_reallocate(a,sizeof(t) * c, 0)
|
||||
#define KRK_ALLOCATE(type, count) (type*)krk_reallocate(NULL,0,sizeof(type)*(count))
|
||||
|
||||
/**
|
||||
* @brief Resize an allocated heap object.
|
||||
|
@ -133,8 +133,27 @@ typedef struct {
|
||||
KrkString * name; /**< @brief Name of the local */
|
||||
} KrkLocalEntry;
|
||||
|
||||
/**
|
||||
* @brief Map entry of opcode offsets to expressions spans.
|
||||
*
|
||||
* Used for printing tracebacks with underlined expressions.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t bytecodeOffset;
|
||||
uint8_t start;
|
||||
uint8_t midStart;
|
||||
uint8_t midEnd;
|
||||
uint8_t end;
|
||||
} KrkExpressionsMap;
|
||||
|
||||
struct KrkInstance;
|
||||
|
||||
typedef struct {
|
||||
uint32_t instructionOffset; /**< @brief Instruction (operand offset) this jump target applies to */
|
||||
uint16_t intendedTarget; /**< @brief High bytes of the intended target. */
|
||||
uint8_t originalOpcode; /**< @brief Original jump opcode to execute. */
|
||||
} KrkOverlongJump;
|
||||
|
||||
/**
|
||||
* @brief Code object.
|
||||
* @extends KrkObj
|
||||
@ -145,8 +164,8 @@ typedef struct {
|
||||
KrkObj obj; /**< @protected @brief Base */
|
||||
unsigned short requiredArgs; /**< @brief Arity of required (non-default) arguments */
|
||||
unsigned short keywordArgs; /**< @brief Arity of keyword (default) arguments */
|
||||
unsigned short potentialPositionals;
|
||||
unsigned short totalArguments;
|
||||
unsigned short potentialPositionals; /**< @brief Precalculated positional arguments for complex argument processing */
|
||||
unsigned short totalArguments; /**< @brief Total argument cells we can fill in complex argument processing */
|
||||
size_t upvalueCount; /**< @brief Number of upvalues this function collects as a closure */
|
||||
KrkChunk chunk; /**< @brief Bytecode data */
|
||||
KrkString * name; /**< @brief Name of the function */
|
||||
@ -157,6 +176,13 @@ typedef struct {
|
||||
size_t localNameCount; /**< @brief Number of entries in @ref localNames */
|
||||
KrkLocalEntry * localNames; /**< @brief Stores the names of local variables used in the function, for debugging */
|
||||
KrkString * qualname; /**< @brief The dotted name of the function */
|
||||
size_t expressionsCapacity; /**< @brief Capacity of @ref expressions */
|
||||
size_t expressionsCount; /**< @brief Number of entries in @ref expressions */
|
||||
KrkExpressionsMap * expressions; /**< @brief Mapping of bytecode offsets to expression spans for debugging */
|
||||
KrkValue jumpTargets; /**< @brief Possibly a set of jump targets... */
|
||||
KrkOverlongJump * overlongJumps; /**< @brief Pessimal overlong jump container */
|
||||
size_t overlongJumpsCapacity; /**< @brief Number of possible entries in pessimal jump table */
|
||||
size_t overlongJumpsCount; /**< @brief Number of entries in pessimal jump table */
|
||||
} KrkCodeObject;
|
||||
|
||||
|
||||
@ -188,11 +214,11 @@ typedef void (*KrkCleanupCallback)(struct KrkInstance *);
|
||||
*/
|
||||
typedef struct KrkClass {
|
||||
KrkObj obj; /**< @protected @brief Base */
|
||||
struct KrkClass * _class; /**< @brief Metaclass */
|
||||
KrkTable methods; /**< @brief General attributes table */
|
||||
KrkString * name; /**< @brief Name of the class */
|
||||
KrkString * filename; /**< @brief Filename of the original source that defined the codeobject for the class */
|
||||
KrkString * docstring; /**< @brief Storage for the class's docstring */
|
||||
struct KrkClass * base; /**< @brief Pointer to base class implementation */
|
||||
KrkTable methods; /**< @brief General attributes table */
|
||||
size_t allocSize; /**< @brief Size to allocate when creating instances of this class */
|
||||
KrkCleanupCallback _ongcscan; /**< @brief C function to call when the garbage collector visits an instance of this class in the scan phase */
|
||||
KrkCleanupCallback _ongcsweep; /**< @brief C function to call when the garbage collector is discarding an instance of this class */
|
||||
@ -238,6 +264,8 @@ typedef struct KrkClass {
|
||||
KrkObj * _pos;
|
||||
KrkObj * _setattr;
|
||||
KrkObj * _format;
|
||||
KrkObj * _new;
|
||||
KrkObj * _bool;
|
||||
|
||||
size_t cacheIndex;
|
||||
} KrkClass;
|
||||
@ -356,8 +384,8 @@ struct DictValues {
|
||||
*/
|
||||
struct KrkModule {
|
||||
KrkInstance inst;
|
||||
#ifndef STATIC_ONLY
|
||||
dlRefType libHandle;
|
||||
#ifndef KRK_STATIC_ONLY
|
||||
krk_dlRefType libHandle;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -111,6 +111,8 @@ typedef enum {
|
||||
TOKEN_RETRY,
|
||||
TOKEN_ERROR,
|
||||
TOKEN_EOF,
|
||||
|
||||
TOKEN_ELLIPSIS, /* ... */
|
||||
} KrkTokenType;
|
||||
|
||||
/**
|
||||
|
@ -10,9 +10,9 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include "kuroko.h"
|
||||
#include "value.h"
|
||||
#include "threads.h"
|
||||
|
||||
/**
|
||||
* @brief One (key,value) pair in a table.
|
||||
@ -26,9 +26,11 @@ typedef struct {
|
||||
* @brief Simple hash table of arbitrary keys to values.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
KrkTableEntry * entries;
|
||||
size_t count; /**< Number of actual items in the dict. */
|
||||
size_t capacity; /**< Size (in items) of each of the entries/indexes arrays */
|
||||
size_t used; /**< Next insertion index in the entries array */
|
||||
KrkTableEntry * entries; /**< Key-value pairs, in insertion order (with KWARGS_VAL(0) gaps) */
|
||||
ssize_t * indexes; /**< Actual hash map: indexes into the key-value pairs. */
|
||||
} KrkTable;
|
||||
|
||||
/**
|
||||
@ -153,21 +155,6 @@ extern int krk_tableDelete(KrkTable * table, KrkValue key);
|
||||
*/
|
||||
extern int krk_tableDeleteExact(KrkTable * table, KrkValue key);
|
||||
|
||||
/**
|
||||
* @brief Internal table scan function.
|
||||
* @memberof KrkTable
|
||||
*
|
||||
* Scans through the the entry array 'entries' to find the appropriate entry
|
||||
* for 'key', return a pointer to the entry, which may be or may not have
|
||||
* an associated pair.
|
||||
*
|
||||
* @param entries Table entry array to scan.
|
||||
* @param capacity Size of the table entry array, in entries.
|
||||
* @param key Key to locate.
|
||||
* @return A pointer to the entry for 'key'.
|
||||
*/
|
||||
extern KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue key);
|
||||
|
||||
/**
|
||||
* @brief Calculate the hash for a value.
|
||||
* @memberof KrkValue
|
||||
|
@ -33,6 +33,30 @@
|
||||
#define _noexport
|
||||
#endif
|
||||
|
||||
#if __has_attribute(unused)
|
||||
# define _unused __attribute__((unused))
|
||||
#else
|
||||
# define _unused
|
||||
#endif
|
||||
|
||||
#if __has_attribute(hot)
|
||||
# define _hot __attribute__((hot))
|
||||
#else
|
||||
# define _hot
|
||||
#endif
|
||||
|
||||
#if __has_attribute(cold)
|
||||
# define _cold __attribute__((cold))
|
||||
#else
|
||||
# define _cold
|
||||
#endif
|
||||
|
||||
#if __has_attribute(nonnull)
|
||||
# define _nonnull __attribute__((nonnull))
|
||||
#else
|
||||
# define _nonnull
|
||||
#endif
|
||||
|
||||
#define ADD_BASE_CLASS(obj, name, baseClass) krk_makeClass(vm.builtins, &obj, name, baseClass)
|
||||
|
||||
#define ATTRIBUTE_NOT_ASSIGNABLE() do { if (unlikely(argc != 1)) return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", \
|
||||
@ -70,29 +94,31 @@
|
||||
#define CHECK_ARG(i, type, ctype, name) \
|
||||
if (unlikely(argc < (i+1))) return NOT_ENOUGH_ARGS(name); \
|
||||
if (unlikely(!IS_ ## type (argv[i]))) return TYPE_ERROR(type,argv[i]); \
|
||||
ctype name __attribute__((unused)) = AS_ ## type (argv[i])
|
||||
ctype name _unused = AS_ ## type (argv[i])
|
||||
|
||||
#define FUNC_NAME(klass, name) _ ## klass ## _ ## name
|
||||
#define FUNC_SIG(klass, name) _noexport KrkValue FUNC_NAME(klass,name) (int argc, const KrkValue argv[], int hasKw)
|
||||
|
||||
/* These forms are deprecated. */
|
||||
#define KRK_METHOD(klass, name, ...) FUNC_SIG(klass, name) { \
|
||||
static __attribute__ ((unused)) const char* _method_name = # name; \
|
||||
CHECK_ARG(0,klass,CURRENT_CTYPE,CURRENT_NAME); \
|
||||
__VA_ARGS__ \
|
||||
return NONE_VAL(); }
|
||||
|
||||
#define KRK_FUNC(name,...) static KrkValue _krk_ ## name (int argc, const KrkValue argv[], int hasKw) { \
|
||||
static __attribute__ ((unused)) const char* _method_name = # name; \
|
||||
__VA_ARGS__ \
|
||||
return NONE_VAL(); }
|
||||
|
||||
/* This assumes you have a KrkInstance called `module` in the current scope. */
|
||||
#define MAKE_CLASS(klass) do { krk_makeClass(module,&klass,#klass,vm.baseClasses->objectClass); klass ->allocSize = sizeof(struct klass); } while (0)
|
||||
#define BIND_METHOD(klass,method) krk_defineNative(&klass->methods, #method, _ ## klass ## _ ## method)
|
||||
#define BIND_PROP(klass,method) krk_defineNativeProperty(&klass->methods, #method, _ ## klass ## _ ## method)
|
||||
#define BIND_FUNC(module,func) krk_defineNative(&module->fields, #func, _krk_ ## func)
|
||||
|
||||
static inline KrkNative * krk_defineNativeStaticMethod(KrkTable * table, const char * name, NativeFn function) {
|
||||
KrkNative * out = krk_defineNative(table,name,function);
|
||||
out->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
|
||||
return out;
|
||||
}
|
||||
#define BIND_STATICMETHOD(klass,method) krk_defineNativeStaticMethod(&klass->methods, #method, _ ## klass ## _ ## method)
|
||||
|
||||
static inline KrkNative * krk_defineNativeClassMethod(KrkTable * table, const char * name, NativeFn function) {
|
||||
KrkNative * out = krk_defineNative(table,name,function);
|
||||
out->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
|
||||
return out;
|
||||
}
|
||||
#define BIND_CLASSMETHOD(klass,method) krk_defineNativeClassMethod(&klass->methods, #method, _ ## klass ## _ ## method)
|
||||
|
||||
#define KRK_Method_internal_name(klass, name) \
|
||||
_krk_method_ ## klass ## _ ## name
|
||||
#define KRK_Method_internal_sig(klass, name) \
|
||||
@ -120,6 +146,16 @@
|
||||
} \
|
||||
KRK_Function_internal_sig(name)
|
||||
|
||||
#define KRK_StaticMethod_internal_sig(klass, name) \
|
||||
static inline KrkValue KRK_Method_internal_name(klass, name) (const char * _method_name, int argc, const KrkValue argv[], int hasKw)
|
||||
#define KRK_StaticMethod(klass, name) \
|
||||
KRK_StaticMethod_internal_sig(klass, name); \
|
||||
FUNC_SIG(klass, name) { \
|
||||
static const char * _method_name = # name; \
|
||||
return KRK_Method_internal_name(klass,name)(_method_name,argc,argv,hasKw); \
|
||||
} \
|
||||
KRK_StaticMethod_internal_sig(klass,name)
|
||||
|
||||
/**
|
||||
* @brief Inline flexible string array.
|
||||
*/
|
||||
@ -240,7 +276,7 @@ extern KrkValue FUNC_NAME(str,format)(int,const KrkValue*,int);
|
||||
#define krk_string_format FUNC_NAME(str,format)
|
||||
|
||||
static inline void _setDoc_class(KrkClass * thing, const char * text, size_t size) {
|
||||
thing->docstring = krk_copyString(text, size);
|
||||
krk_attachNamedObject(&thing->methods, "__doc__", (KrkObj*)krk_copyString(text, size));
|
||||
}
|
||||
static inline void _setDoc_instance(KrkInstance * thing, const char * text, size_t size) {
|
||||
krk_attachNamedObject(&thing->fields, "__doc__", (KrkObj*)krk_copyString(text, size));
|
||||
@ -328,4 +364,19 @@ extern int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char *
|
||||
extern int krk_pushStringBuilderFormat(struct StringBuilder * sb, const char * fmt, ...);
|
||||
extern KrkValue krk_stringFromFormat(const char * fmt, ...);
|
||||
extern int krk_long_to_int(KrkValue val, char size, void * out);
|
||||
extern int krk_isSubClass(const KrkClass * cls, const KrkClass * base);
|
||||
|
||||
#define KRK_Module_internal_name(name) \
|
||||
_krk_module_onload_ ## name
|
||||
#define KRK_Module_internal_sig(name) \
|
||||
static inline void KRK_Module_internal_name(name) (KrkInstance * module, KrkString * runAs)
|
||||
#define KRK_Module(name) \
|
||||
KRK_Module_internal_sig(name); \
|
||||
KrkValue krk_module_onload_ ## name (KrkString * runAs) { \
|
||||
KrkInstance * module = krk_newInstance(KRK_BASE_CLASS(module)); \
|
||||
krk_push(OBJECT_VAL(module)); \
|
||||
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)runAs); \
|
||||
KRK_Module_internal_name(name)(module, runAs); \
|
||||
return krk_pop(); \
|
||||
} \
|
||||
KRK_Module_internal_sig(name)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
#include "kuroko.h"
|
||||
|
||||
#ifndef KRK_NO_NAN_BOXING
|
||||
/**
|
||||
* @brief Tag enum for basic value types.
|
||||
*
|
||||
@ -23,28 +24,6 @@ typedef enum {
|
||||
KRK_VAL_NOTIMPL = 0x7FFE,
|
||||
} KrkValueType;
|
||||
|
||||
/*
|
||||
* The following poorly-named macros define bit patterns for identifying
|
||||
* various boxed types.
|
||||
*
|
||||
* Boxing is done by first setting all of the bits of MASK_NAN. If all of
|
||||
* these bits are set, a value is not a float. If any of them are not set,
|
||||
* then a value is a float - and possibly a real NaN.
|
||||
*
|
||||
* Three other bits - one before and two after the MASK_NAN bits - determine
|
||||
* what type the value actually is. KWARGS sets none of the identifying bits,
|
||||
* NONE sets all of them.
|
||||
*/
|
||||
#define KRK_VAL_MASK_BOOLEAN ((uint64_t)0xFFFC000000000000) /* 1..1100 */
|
||||
#define KRK_VAL_MASK_INTEGER ((uint64_t)0xFFFD000000000000) /* 1..1101 */
|
||||
#define KRK_VAL_MASK_HANDLER ((uint64_t)0xFFFE000000000000) /* 1..1110 */
|
||||
#define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000) /* 1..1111 */
|
||||
#define KRK_VAL_MASK_KWARGS ((uint64_t)0x7FFC000000000000) /* 0..1100 */
|
||||
#define KRK_VAL_MASK_OBJECT ((uint64_t)0x7FFD000000000000) /* 0..1101 */
|
||||
#define KRK_VAL_MASK_NOTIMPL ((uint64_t)0x7FFE000000000000) /* 0..1110 */
|
||||
#define KRK_VAL_MASK_NAN ((uint64_t)0x7FFC000000000000)
|
||||
#define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)
|
||||
|
||||
/**
|
||||
* @struct KrkValue
|
||||
* @brief Stack reference or primative value.
|
||||
@ -61,6 +40,32 @@ typedef enum {
|
||||
*/
|
||||
typedef uint64_t KrkValue;
|
||||
|
||||
#define _krk_valuesSame(a,b) (a == b)
|
||||
|
||||
#else
|
||||
/*
|
||||
* Tagged union, but without the union fun.
|
||||
*/
|
||||
typedef enum {
|
||||
KRK_VAL_NONE = 0,
|
||||
KRK_VAL_INTEGER = 1,
|
||||
KRK_VAL_BOOLEAN = 2,
|
||||
KRK_VAL_HANDLER = 4,
|
||||
KRK_VAL_KWARGS = 8,
|
||||
KRK_VAL_OBJECT = 16,
|
||||
KRK_VAL_NOTIMPL = 32,
|
||||
KRK_VAL_FLOATING = 64,
|
||||
} KrkValueType;
|
||||
|
||||
typedef struct {
|
||||
uint64_t tag;
|
||||
uint64_t val;
|
||||
} KrkValue;
|
||||
|
||||
#define _krk_valuesSame(a,b) (memcmp(&(a),&(b),sizeof(KrkValue)) == 0)
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Flexible vector of stack references.
|
||||
*
|
||||
@ -110,42 +115,6 @@ extern void krk_writeValueArray(KrkValueArray * array, KrkValue value);
|
||||
*/
|
||||
extern void krk_freeValueArray(KrkValueArray * array);
|
||||
|
||||
/**
|
||||
* @brief Print a string representation of a value.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Print a string representation of 'value' to the stream 'f'.
|
||||
* For primitives, performs appropriate formatting. For objects,
|
||||
* this will call __str__ on the object's representative type.
|
||||
* If the type does not have a __str__ method, __repr__ will be
|
||||
* tried before falling back to krk_typeName to directly print
|
||||
* the name of the class with no information on the value.
|
||||
*
|
||||
* This function provides the backend for the print() built-in.
|
||||
*
|
||||
* @param f Stream to write to.
|
||||
* @param value Value to display.
|
||||
*/
|
||||
extern void krk_printValue(FILE * f, KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Print a value without calling the VM.
|
||||
* @memberof KrkValue
|
||||
*
|
||||
* Print a string representation of 'value' to the stream 'f',
|
||||
* avoiding calls to managed code by using simplified representations
|
||||
* where necessary. This is intended for use in debugging code, such
|
||||
* as during disassembly, or when printing values in an untrusted context.
|
||||
*
|
||||
* @note This function will truncate long strings and print them in a form
|
||||
* closer to the 'repr()' representation, with escaped bytes, rather
|
||||
* than directly printing them to the stream.
|
||||
*
|
||||
* @param f Stream to write to.
|
||||
* @param value Value to display.
|
||||
*/
|
||||
extern void krk_printValueSafe(FILE * f, KrkValue value);
|
||||
|
||||
/**
|
||||
* @brief Compare two values for equality.
|
||||
* @memberof KrkValue
|
||||
@ -169,7 +138,7 @@ extern int krk_valuesEqual(KrkValue a, KrkValue b);
|
||||
*
|
||||
* @return 1 if values represent the same object or value, 0 otherwise.
|
||||
*/
|
||||
extern int krk_valuesSame(KrkValue a, KrkValue b);
|
||||
static inline int krk_valuesSame(KrkValue a, KrkValue b) { return _krk_valuesSame(a,b); }
|
||||
|
||||
/**
|
||||
* @brief Compare two values by identity, then by equality.
|
||||
@ -182,12 +151,37 @@ extern int krk_valuesSame(KrkValue a, KrkValue b);
|
||||
extern int krk_valuesSameOrEqual(KrkValue a, KrkValue b);
|
||||
|
||||
extern KrkValue krk_parse_int(const char * start, size_t width, unsigned int base);
|
||||
extern KrkValue krk_parse_float(const char* start, size_t width);
|
||||
|
||||
#ifndef KRK_NO_NAN_BOXING
|
||||
|
||||
typedef union {
|
||||
KrkValue val;
|
||||
double dbl;
|
||||
} KrkValueDbl;
|
||||
|
||||
/*
|
||||
* The following poorly-named macros define bit patterns for identifying
|
||||
* various boxed types.
|
||||
*
|
||||
* Boxing is done by first setting all of the bits of MASK_NAN. If all of
|
||||
* these bits are set, a value is not a float. If any of them are not set,
|
||||
* then a value is a float - and possibly a real NaN.
|
||||
*
|
||||
* Three other bits - one before and two after the MASK_NAN bits - determine
|
||||
* what type the value actually is. KWARGS sets none of the identifying bits,
|
||||
* NONE sets all of them.
|
||||
*/
|
||||
#define KRK_VAL_MASK_BOOLEAN ((uint64_t)0xFFFC000000000000) /* 1..1100 */
|
||||
#define KRK_VAL_MASK_INTEGER ((uint64_t)0xFFFD000000000000) /* 1..1101 */
|
||||
#define KRK_VAL_MASK_HANDLER ((uint64_t)0xFFFE000000000000) /* 1..1110 */
|
||||
#define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000) /* 1..1111 */
|
||||
#define KRK_VAL_MASK_KWARGS ((uint64_t)0x7FFC000000000000) /* 0..1100 */
|
||||
#define KRK_VAL_MASK_OBJECT ((uint64_t)0x7FFD000000000000) /* 0..1101 */
|
||||
#define KRK_VAL_MASK_NOTIMPL ((uint64_t)0x7FFE000000000000) /* 0..1110 */
|
||||
#define KRK_VAL_MASK_NAN ((uint64_t)0x7FFC000000000000)
|
||||
#define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)
|
||||
|
||||
#ifdef KRK_SANITIZE_OBJECT_POINTERS
|
||||
/**
|
||||
* Debugging tool for verifying we aren't trying to box NULL, which is not a valid object.
|
||||
@ -213,13 +207,13 @@ static inline uintptr_t _krk_sanitize(uintptr_t input) {
|
||||
#define KRK_HEAP_TAG 0
|
||||
#endif
|
||||
|
||||
#define NONE_VAL(value) ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NONE))
|
||||
#define NOTIMPL_VAL(value) ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NOTIMPL))
|
||||
#define NONE_VAL() ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NONE))
|
||||
#define NOTIMPL_VAL() ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NOTIMPL))
|
||||
#define BOOLEAN_VAL(value) ((KrkValue)(((uint64_t)(value) & KRK_VAL_MASK_LOW) | KRK_VAL_MASK_BOOLEAN))
|
||||
#define INTEGER_VAL(value) ((KrkValue)(((uint64_t)(value) & KRK_VAL_MASK_LOW) | KRK_VAL_MASK_INTEGER))
|
||||
#define KWARGS_VAL(value) ((KrkValue)((uint32_t)(value) | KRK_VAL_MASK_KWARGS))
|
||||
#define OBJECT_VAL(value) ((KrkValue)((_krk_sanitize((uintptr_t)(value)) & KRK_VAL_MASK_LOW) | KRK_VAL_MASK_OBJECT))
|
||||
#define HANDLER_VAL(ty,ta) ((KrkValue)((uint32_t)((((uint16_t)ty) << 16) | ((uint16_t)ta)) | KRK_VAL_MASK_HANDLER))
|
||||
#define HANDLER_VAL(ty,ta) ((KrkValue)((uint64_t)((((uint64_t)ty) << 32) | ((uint32_t)ta)) | KRK_VAL_MASK_HANDLER))
|
||||
#define FLOATING_VAL(value) (((KrkValueDbl){.dbl = (value)}).val)
|
||||
|
||||
#define KRK_VAL_TYPE(value) ((value) >> 48)
|
||||
@ -230,7 +224,7 @@ static inline uintptr_t _krk_sanitize(uintptr_t input) {
|
||||
#define AS_BOOLEAN(value) AS_INTEGER(value)
|
||||
|
||||
#define AS_NOTIMPL(value) ((krk_integer_type)((value) & KRK_VAL_MASK_LOW))
|
||||
#define AS_HANDLER(value) ((uint32_t)((value) & KRK_VAL_MASK_LOW))
|
||||
#define AS_HANDLER(value) ((uint64_t)((value) & KRK_VAL_MASK_LOW))
|
||||
#define AS_OBJECT(value) ((KrkObj*)(uintptr_t)(((value) & KRK_VAL_MASK_LOW) | KRK_HEAP_TAG))
|
||||
#define AS_FLOATING(value) (((KrkValueDbl){.val = (value)}).dbl)
|
||||
|
||||
@ -249,8 +243,49 @@ static inline uintptr_t _krk_sanitize(uintptr_t input) {
|
||||
/* ... and as we said above, if any of the MASK_NAN bits are unset, it's a float. */
|
||||
#define IS_FLOATING(value) (((value) & KRK_VAL_MASK_NAN) != KRK_VAL_MASK_NAN)
|
||||
|
||||
#define AS_HANDLER_TYPE(value) (AS_HANDLER(value) >> 16)
|
||||
#define AS_HANDLER_TARGET(value) (AS_HANDLER(value) & 0xFFFF)
|
||||
#else
|
||||
|
||||
typedef union {
|
||||
uint64_t val;
|
||||
double dbl;
|
||||
} KrkValueDbl;
|
||||
|
||||
#define NONE_VAL() ((KrkValue){KRK_VAL_NONE,-1})
|
||||
#define NOTIMPL_VAL() ((KrkValue){KRK_VAL_NOTIMPL,0})
|
||||
#define BOOLEAN_VAL(value) ((KrkValue){KRK_VAL_BOOLEAN,!!(value)})
|
||||
#define INTEGER_VAL(value) ((KrkValue){KRK_VAL_INTEGER,((uint64_t)(value)) & 0xFFFFffffFFFFULL})
|
||||
#define KWARGS_VAL(value) ((KrkValue){KRK_VAL_KWARGS,((uint32_t)(value))})
|
||||
#define OBJECT_VAL(value) ((KrkValue){KRK_VAL_OBJECT,((uintptr_t)(value))})
|
||||
#define HANDLER_VAL(ty,ta) ((KrkValue){KRK_VAL_HANDLER,((uint64_t)((((uint64_t)ty) << 32) | ((uint32_t)ta)))})
|
||||
#define FLOATING_VAL(value) ((KrkValue){KRK_VAL_FLOATING,(((KrkValueDbl){.dbl = (value)}).val)})
|
||||
|
||||
#define KRK_VAL_TYPE(value) ((value).tag)
|
||||
|
||||
#define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000)
|
||||
#define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)
|
||||
#define KRK_IX(value) ((uint64_t)((value).val & KRK_VAL_MASK_LOW))
|
||||
#define KRK_SX(value) ((uint64_t)((value).val & 0x800000000000))
|
||||
#define AS_INTEGER(value) ((krk_integer_type)(KRK_SX(value) ? (KRK_IX(value) | KRK_VAL_MASK_NONE) : (KRK_IX(value))))
|
||||
#define AS_BOOLEAN(value) AS_INTEGER(value)
|
||||
|
||||
#define AS_HANDLER(value) ((uint64_t)((value)).val)
|
||||
#define AS_OBJECT(value) ((KrkObj*)((uintptr_t)((value).val)))
|
||||
#define AS_FLOATING(value) (((KrkValueDbl){.val = ((value)).val}).dbl)
|
||||
|
||||
#define IS_INTEGER(value) (!!(((value)).tag & (KRK_VAL_INTEGER|KRK_VAL_BOOLEAN)))
|
||||
#define IS_BOOLEAN(value) (((value)).tag == KRK_VAL_BOOLEAN)
|
||||
#define IS_NONE(value) (((value)).tag == KRK_VAL_NONE)
|
||||
#define IS_HANDLER(value) (((value)).tag == KRK_VAL_HANDLER)
|
||||
#define IS_OBJECT(value) (((value)).tag == KRK_VAL_OBJECT)
|
||||
#define IS_KWARGS(value) (((value)).tag == KRK_VAL_KWARGS)
|
||||
#define IS_NOTIMPL(value) (((value)).tag == KRK_VAL_NOTIMPL)
|
||||
#define IS_FLOATING(value) (((value)).tag == KRK_VAL_FLOATING)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define AS_HANDLER_TYPE(value) (AS_HANDLER(value) >> 32)
|
||||
#define AS_HANDLER_TARGET(value) (AS_HANDLER(value) & 0xFFFFFFFF)
|
||||
#define IS_HANDLER_TYPE(value,type) (IS_HANDLER(value) && AS_HANDLER_TYPE(value) == type)
|
||||
|
||||
#define KWARGS_SINGLE (INT32_MAX)
|
||||
|
@ -7,9 +7,7 @@
|
||||
* for Kuroko, including initializing the VM and passing code to be interpreted.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include "kuroko.h"
|
||||
#include "value.h"
|
||||
#include "table.h"
|
||||
@ -19,7 +17,7 @@
|
||||
* @def KRK_CALL_FRAMES_MAX
|
||||
* @brief Maximum depth of the call stack in managed-code function calls.
|
||||
*/
|
||||
#define KRK_CALL_FRAMES_MAX 64
|
||||
#define KRK_CALL_FRAMES_MAX 1000
|
||||
|
||||
/**
|
||||
* @def KRK_THREAD_SCRATCH_SIZE
|
||||
@ -50,9 +48,6 @@ typedef struct {
|
||||
size_t outSlots; /**< Offset into the stack at which stackTop will be reset upon return */
|
||||
KrkTable * globals; /**< Pointer to the attribute table containing valud global vairables for this call */
|
||||
KrkValue globalsOwner; /**< Owner of the current globals context, to give to new closures. */
|
||||
#ifndef KRK_NO_CALLGRIND
|
||||
struct timespec in_time;
|
||||
#endif
|
||||
} KrkCallFrame;
|
||||
|
||||
/**
|
||||
@ -136,16 +131,13 @@ struct BaseClasses {
|
||||
KrkClass * enumerateClass; /**< Yield pairs of indexes and values from an iterator. */
|
||||
KrkClass * HelperClass; /**< Class implementation of 'help' object */
|
||||
KrkClass * LicenseReaderClass; /**< Class implementation of 'license' object */
|
||||
KrkClass * FileClass; /**< os.File */
|
||||
KrkClass * BinaryFileClass; /**< os.BinaryFile */
|
||||
KrkClass * DirectoryClass; /**< os.Directory */
|
||||
KrkClass * stat_resultClass; /**< stat.stat_result */
|
||||
KrkClass * EnvironClass; /**< os._Environ */
|
||||
KrkClass * CompilerStateClass; /**< Compiler global state */
|
||||
KrkClass * CellClass; /**< Upvalue cell */
|
||||
KrkClass * setClass; /**< Unordered hashset */
|
||||
KrkClass * setiteratorClass; /**< Iterator over values in a set */
|
||||
KrkClass * ThreadClass; /**< Threading.Thread */
|
||||
KrkClass * LockClass; /**< Threading.Lock */
|
||||
KrkClass * CompilerStateClass; /**< Compiler global state */
|
||||
KrkClass * ellipsisClass; /**< Type of the Ellipsis (...) singleton */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -171,6 +163,7 @@ typedef struct KrkThreadState {
|
||||
KrkInstance * module; /**< The current module execution context. */
|
||||
KrkValue currentException; /**< When an exception is thrown, it is stored here. */
|
||||
int flags; /**< Thread-local VM flags; each thread inherits the low byte of the global VM flags. */
|
||||
unsigned int maximumCallDepth; /**< Maximum recursive call depth. */
|
||||
KrkValue * stackMax; /**< End of allocated stack space. */
|
||||
|
||||
KrkValue scratchSpace[KRK_THREAD_SCRATCH_SIZE]; /**< A place to store a few values to keep them from being prematurely GC'd. */
|
||||
@ -204,8 +197,6 @@ typedef struct KrkVM {
|
||||
KrkObj** grayStack; /**< Scan list */
|
||||
|
||||
KrkThreadState * threads; /**< Invasive linked list of all VM threads. */
|
||||
FILE * callgrindFile; /**< File to write unprocessed callgrind data to. */
|
||||
size_t maximumCallDepth; /**< Maximum recursive call depth. */
|
||||
struct DebuggerState * dbgState; /**< Opaque debugger state pointer. */
|
||||
} KrkVM;
|
||||
|
||||
@ -222,15 +213,15 @@ typedef struct KrkVM {
|
||||
#define KRK_GLOBAL_ENABLE_STRESS_GC (1 << 8)
|
||||
#define KRK_GLOBAL_GC_PAUSED (1 << 9)
|
||||
#define KRK_GLOBAL_CLEAN_OUTPUT (1 << 10)
|
||||
#define KRK_GLOBAL_CALLGRIND (1 << 11)
|
||||
/* 11 is available again */
|
||||
#define KRK_GLOBAL_REPORT_GC_COLLECTS (1 << 12)
|
||||
#define KRK_GLOBAL_THREADS (1 << 13)
|
||||
#define KRK_GLOBAL_NO_DEFAULT_MODULES (1 << 14)
|
||||
|
||||
#ifndef KRK_DISABLE_THREADS
|
||||
# define threadLocal __thread
|
||||
# define krk_threadLocal __thread
|
||||
#else
|
||||
# define threadLocal
|
||||
# define krk_threadLocal
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -251,7 +242,7 @@ inline KrkThreadState * _macos_currentThread(void) {
|
||||
#elif !defined(KRK_DISABLE_THREADS) && ((defined(_WIN32) && !defined(KRKINLIB)) || defined(KRK_MEDIOCRE_TLS))
|
||||
#define krk_currentThread (*krk_getCurrentThread())
|
||||
#else
|
||||
extern threadLocal KrkThreadState krk_currentThread;
|
||||
extern krk_threadLocal KrkThreadState krk_currentThread;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -320,7 +311,7 @@ extern void krk_resetStack(void);
|
||||
* indicate @c KRK_THREAD_HAS_EXCEPTION and @c krk_currentThread.currentException
|
||||
* should contain the raised exception value.
|
||||
*/
|
||||
extern KrkValue krk_interpret(const char * src, char * fromFile);
|
||||
extern KrkValue krk_interpret(const char * src, const char * fromFile);
|
||||
|
||||
/**
|
||||
* @brief Load and run a source file and return when execution completes.
|
||||
@ -334,7 +325,7 @@ extern KrkValue krk_interpret(const char * src, char * fromFile);
|
||||
* @return As with @c krk_interpret, an object representing the newly created module,
|
||||
* or the final return value of the VM execution.
|
||||
*/
|
||||
extern KrkValue krk_runfile(const char * fileName, char * fromFile);
|
||||
extern KrkValue krk_runfile(const char * fileName, const char * fromFile);
|
||||
|
||||
/**
|
||||
* @brief Push a stack value.
|
||||
@ -596,10 +587,12 @@ extern int krk_isInstanceOf(KrkValue obj, const KrkClass * type);
|
||||
* @memberof KrkClass
|
||||
*
|
||||
* Performs attribute lookup from the class @p _class for @p name.
|
||||
* If @p name is not a valid method, the binding fails.
|
||||
* If @p name is not a valid member, the binding fails.
|
||||
* If @p name is a valid method, the method will be retrieved and
|
||||
* bound to the instance on the top of the stack, replacing it
|
||||
* with a @ref BoundMethod object.
|
||||
* If @p name is not a method, the unbound attribute is returned.
|
||||
* If @p name is a descriptor, the @c %__get__ method is executed.
|
||||
*
|
||||
* @param _class Class object to resolve methods from.
|
||||
* @param name String object with the name of the method to resolve.
|
||||
@ -607,6 +600,22 @@ extern int krk_isInstanceOf(KrkValue obj, const KrkClass * type);
|
||||
*/
|
||||
extern int krk_bindMethod(KrkClass * _class, KrkString * name);
|
||||
|
||||
/**
|
||||
* @brief Bind a method with super() semantics
|
||||
* @memberof KrkClass
|
||||
*
|
||||
* @see krk_bindMethod
|
||||
*
|
||||
* Allows binding potential class methods with the correct class object while
|
||||
* searching from a base class. Used by the @c super() mechanism.
|
||||
*
|
||||
* @param baseClass The superclass to begin searching from.
|
||||
* @param name The name of the member to look up.
|
||||
* @param realClass The class to bind if a class method is found.
|
||||
* @return 1 if a member has been found, 0 if binding fails.
|
||||
*/
|
||||
extern int krk_bindMethodSuper(KrkClass * baseClass, KrkString * name, KrkClass * realClass);
|
||||
|
||||
/**
|
||||
* @brief Call a callable value in the current stack context.
|
||||
* @memberof KrkValue
|
||||
@ -976,33 +985,6 @@ extern int krk_delAttribute(KrkString * name);
|
||||
*/
|
||||
extern void krk_module_init_kuroko(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the built-in 'gc' module.
|
||||
*/
|
||||
extern void krk_module_init_gc(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the built-in 'time' module.
|
||||
*/
|
||||
extern void krk_module_init_time(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the built-in 'os' module.
|
||||
*/
|
||||
extern void krk_module_init_os(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the built-in 'fileio' module.
|
||||
*/
|
||||
extern void krk_module_init_fileio(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the built-in 'dis' module.
|
||||
*
|
||||
* Not available if KRK_DISABLE_DEBUG is set.
|
||||
*/
|
||||
extern void krk_module_init_dis(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the built-in 'threading' module.
|
||||
*
|
||||
|
83
src/memory.c
83
src/memory.c
@ -1,3 +1,4 @@
|
||||
#include <time.h>
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/memory.h>
|
||||
#include <kuroko/object.h>
|
||||
@ -7,6 +8,8 @@
|
||||
|
||||
#include "private.h"
|
||||
|
||||
#define FREE_OBJECT(t,p) krk_reallocate(p,sizeof(t),0)
|
||||
|
||||
#if defined(KRK_EXTENSIVE_MEMORY_DEBUGGING)
|
||||
/**
|
||||
* Extensive Memory Debugging
|
||||
@ -18,7 +21,7 @@
|
||||
* the sizes of objects by both using the appropriate macros and by
|
||||
* ensuring the right sizes are passed to those macros. This is a very
|
||||
* easy thing to get wrong - allocate with @c malloc but free with the
|
||||
* @c FREE_ARRAY macros, for example, and the memory tracking now has
|
||||
* @c KRK_FREE_ARRAY macros, for example, and the memory tracking now has
|
||||
* a net negative, which may lead to underflowing. Use the right macros,
|
||||
* but mix up sizes between allocation and deallocation, and we may have
|
||||
* a "leak" of bytes and garbage collection may happen more often than
|
||||
@ -202,9 +205,9 @@ static void freeObject(KrkObj * object) {
|
||||
switch (object->type) {
|
||||
case KRK_OBJ_STRING: {
|
||||
KrkString * string = (KrkString*)object;
|
||||
FREE_ARRAY(char, string->chars, string->length + 1);
|
||||
KRK_FREE_ARRAY(char, string->chars, string->length + 1);
|
||||
if (string->codes && string->codes != string->chars) free(string->codes);
|
||||
FREE(KrkString, object);
|
||||
FREE_OBJECT(KrkString, object);
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_CODEOBJECT: {
|
||||
@ -212,24 +215,26 @@ static void freeObject(KrkObj * object) {
|
||||
krk_freeChunk(&function->chunk);
|
||||
krk_freeValueArray(&function->positionalArgNames);
|
||||
krk_freeValueArray(&function->keywordArgNames);
|
||||
FREE_ARRAY(KrkLocalEntry, function->localNames, function->localNameCount);
|
||||
KRK_FREE_ARRAY(KrkLocalEntry, function->localNames, function->localNameCount);
|
||||
KRK_FREE_ARRAY(KrkExpressionsMap, function->expressions, function->expressionsCapacity);
|
||||
KRK_FREE_ARRAY(KrkOverlongJump, function->overlongJumps, function->overlongJumpsCapacity);
|
||||
function->localNameCount = 0;
|
||||
FREE(KrkCodeObject, object);
|
||||
FREE_OBJECT(KrkCodeObject, object);
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_NATIVE: {
|
||||
FREE(KrkNative, object);
|
||||
FREE_OBJECT(KrkNative, object);
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_CLOSURE: {
|
||||
KrkClosure * closure = (KrkClosure*)object;
|
||||
FREE_ARRAY(KrkUpvalue*,closure->upvalues,closure->upvalueCount);
|
||||
KRK_FREE_ARRAY(KrkUpvalue*,closure->upvalues,closure->upvalueCount);
|
||||
krk_freeTable(&closure->fields);
|
||||
FREE(KrkClosure, object);
|
||||
FREE_OBJECT(KrkClosure, object);
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_UPVALUE: {
|
||||
FREE(KrkUpvalue, object);
|
||||
FREE_OBJECT(KrkUpvalue, object);
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_CLASS: {
|
||||
@ -239,7 +244,7 @@ static void freeObject(KrkObj * object) {
|
||||
if (_class->base) {
|
||||
krk_tableDeleteExact(&_class->base->subclasses, OBJECT_VAL(object));
|
||||
}
|
||||
FREE(KrkClass, object);
|
||||
FREE_OBJECT(KrkClass, object);
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_INSTANCE: {
|
||||
@ -252,24 +257,24 @@ static void freeObject(KrkObj * object) {
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_BOUND_METHOD:
|
||||
FREE(KrkBoundMethod, object);
|
||||
FREE_OBJECT(KrkBoundMethod, object);
|
||||
break;
|
||||
case KRK_OBJ_TUPLE: {
|
||||
KrkTuple * tuple = (KrkTuple*)object;
|
||||
krk_freeValueArray(&tuple->values);
|
||||
FREE(KrkTuple, object);
|
||||
FREE_OBJECT(KrkTuple, object);
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_BYTES: {
|
||||
KrkBytes * bytes = (KrkBytes*)object;
|
||||
FREE_ARRAY(uint8_t, bytes->bytes, bytes->length);
|
||||
FREE(KrkBytes, bytes);
|
||||
KRK_FREE_ARRAY(uint8_t, bytes->bytes, bytes->length);
|
||||
FREE_OBJECT(KrkBytes, bytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void krk_freeObjects() {
|
||||
void krk_freeObjects(void) {
|
||||
KrkObj * object = vm.objects;
|
||||
KrkObj * other = NULL;
|
||||
|
||||
@ -319,7 +324,7 @@ void krk_markObject(KrkObj * object) {
|
||||
object->flags |= KRK_OBJ_FLAGS_IS_MARKED;
|
||||
|
||||
if (vm.grayCapacity < vm.grayCount + 1) {
|
||||
vm.grayCapacity = GROW_CAPACITY(vm.grayCapacity);
|
||||
vm.grayCapacity = KRK_GROW_CAPACITY(vm.grayCapacity);
|
||||
vm.grayStack = realloc(vm.grayStack, sizeof(KrkObj*) * vm.grayCapacity);
|
||||
if (!vm.grayStack) exit(1);
|
||||
}
|
||||
@ -362,6 +367,7 @@ static void blackenObject(KrkObj * object) {
|
||||
for (size_t i = 0; i < function->localNameCount; ++i) {
|
||||
krk_markObject((KrkObj*)function->localNames[i].name);
|
||||
}
|
||||
krk_markValue(function->jumpTargets);
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_UPVALUE:
|
||||
@ -371,8 +377,8 @@ static void blackenObject(KrkObj * object) {
|
||||
KrkClass * _class = (KrkClass *)object;
|
||||
krk_markObject((KrkObj*)_class->name);
|
||||
krk_markObject((KrkObj*)_class->filename);
|
||||
krk_markObject((KrkObj*)_class->docstring);
|
||||
krk_markObject((KrkObj*)_class->base);
|
||||
krk_markObject((KrkObj*)_class->_class);
|
||||
krk_markTable(&_class->methods);
|
||||
break;
|
||||
}
|
||||
@ -436,7 +442,7 @@ static size_t sweep(void) {
|
||||
}
|
||||
|
||||
void krk_markTable(KrkTable * table) {
|
||||
for (size_t i = 0; i < table->capacity; ++i) {
|
||||
for (size_t i = 0; i < table->used; ++i) {
|
||||
KrkTableEntry * entry = &table->entries[i];
|
||||
krk_markValue(entry->key);
|
||||
krk_markValue(entry->value);
|
||||
@ -444,7 +450,7 @@ void krk_markTable(KrkTable * table) {
|
||||
}
|
||||
|
||||
static void tableRemoveWhite(KrkTable * table) {
|
||||
for (size_t i = 0; i < table->capacity; ++i) {
|
||||
for (size_t i = 0; i < table->used; ++i) {
|
||||
KrkTableEntry * entry = &table->entries[i];
|
||||
if (IS_OBJECT(entry->key) && !((AS_OBJECT(entry->key))->flags & KRK_OBJ_FLAGS_IS_MARKED)) {
|
||||
krk_tableDeleteExact(table, entry->key);
|
||||
@ -562,42 +568,3 @@ size_t krk_collectGarbage(void) {
|
||||
return out;
|
||||
}
|
||||
|
||||
#ifndef KRK_NO_SYSTEM_MODULES
|
||||
KRK_Function(collect) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
if (&krk_currentThread != vm.threads) return krk_runtimeError(vm.exceptions->valueError, "only the main thread can do that");
|
||||
return INTEGER_VAL(krk_collectGarbage());
|
||||
}
|
||||
|
||||
KRK_Function(pause) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
vm.globalFlags |= (KRK_GLOBAL_GC_PAUSED);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Function(resume) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
vm.globalFlags &= ~(KRK_GLOBAL_GC_PAUSED);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
void krk_module_init_gc(void) {
|
||||
/**
|
||||
* gc = module()
|
||||
*
|
||||
* Namespace for methods for controlling the garbage collector.
|
||||
*/
|
||||
KrkInstance * gcModule = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_attachNamedObject(&vm.modules, "gc", (KrkObj*)gcModule);
|
||||
krk_attachNamedObject(&gcModule->fields, "__name__", (KrkObj*)S("gc"));
|
||||
krk_attachNamedValue(&gcModule->fields, "__file__", NONE_VAL());
|
||||
KRK_DOC(gcModule, "@brief Namespace containing methods for controlling the garbage collector.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(gcModule,collect),
|
||||
"@brief Triggers one cycle of garbage collection.");
|
||||
KRK_DOC(BIND_FUNC(gcModule,pause),
|
||||
"@brief Disables automatic garbage collection until @ref resume is called.");
|
||||
KRK_DOC(BIND_FUNC(gcModule,resume),
|
||||
"@brief Re-enable automatic garbage collection after it was stopped by @ref pause ");
|
||||
}
|
||||
#endif
|
||||
|
@ -17,6 +17,7 @@ CACHED_METHOD(DESCGET, "__get__", _descget)
|
||||
CACHED_METHOD(DESCSET, "__set__", _descset)
|
||||
CACHED_METHOD(CLASSGETITEM, "__class_getitem__", _classgetitem)
|
||||
CACHED_METHOD(HASH, "__hash__", _hash)
|
||||
CACHED_METHOD(BOOL, "__bool__", _bool)
|
||||
|
||||
#define BINOPTRIO(name) \
|
||||
CACHED_METHOD(name, "__" #name "__", _ ## name) \
|
||||
@ -47,6 +48,7 @@ CACHED_METHOD(SETNAME, "__set_name__", _set_name)
|
||||
CACHED_METHOD(POS, "__pos__", _pos)
|
||||
CACHED_METHOD(SETATTR, "__setattr__", _setattr)
|
||||
CACHED_METHOD(FORMAT, "__format__", _format)
|
||||
CACHED_METHOD(NEW, "__new__", _new)
|
||||
|
||||
/* These are not methods */
|
||||
SPECIAL_ATTRS(CLASS, "__class__")
|
||||
@ -60,4 +62,10 @@ SPECIAL_ATTRS(CHR, "__chr__")
|
||||
SPECIAL_ATTRS(ORD, "__ord__")
|
||||
SPECIAL_ATTRS(FLOAT, "__float__")
|
||||
SPECIAL_ATTRS(STRSTRIP, " \t\n\r")
|
||||
|
||||
SPECIAL_ATTRS(HEX, "__hex__")
|
||||
SPECIAL_ATTRS(OCT, "__oct__")
|
||||
SPECIAL_ATTRS(BIN, "__bin__")
|
||||
SPECIAL_ATTRS(ABS, "__abs__")
|
||||
SPECIAL_ATTRS(FUNC, "__func__")
|
||||
SPECIAL_ATTRS(BLDCLS, "__build_class__")
|
||||
SPECIAL_ATTRS(MAIN, "__main__")
|
||||
|
315
src/modules/module__pheap.c
Normal file
315
src/modules/module__pheap.c
Normal file
@ -0,0 +1,315 @@
|
||||
/**
|
||||
* @brief Pairing heap.
|
||||
* @file module__pheap.c
|
||||
* @author K. Lange <klange@toaruos.org>
|
||||
*
|
||||
* A very simple pairing heap.
|
||||
*
|
||||
* Provides a min-heap with insert, peek, and pop.
|
||||
*
|
||||
* While heap entries may be mutable, care should be taken not to modify
|
||||
* any values used for comparison, as the heap can not update ordering.
|
||||
*
|
||||
* This could likely be improved by the implementation of parent pointers,
|
||||
* which can allow for elements of the heap other than the root to be
|
||||
* removed or updated (removal + reinsertion), but that requires the
|
||||
* ability to quickly reference specific elements - which requires the
|
||||
* heap "nodes" to also be accessible or addressible in some way, such
|
||||
* as by making them Kuroko objects. Such a change would likely result
|
||||
* in performance impacts, so a parent-pointer pairing heap should be
|
||||
* a separate class.
|
||||
*
|
||||
* The implementation here is based strongly on the pseudocode found in
|
||||
* the Wikipedia article "Paring heap".
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
static KrkClass * PHeapClass;
|
||||
|
||||
/**
|
||||
* @brief Heap node.
|
||||
*
|
||||
* Represents one element in the heap. Each element potentially has
|
||||
* a pointer to more elements (a "right" or "next" pointer) and a
|
||||
* pointer to a subheap (a "left" pointer).
|
||||
*/
|
||||
typedef struct PHeap PHeap;
|
||||
struct PHeap {
|
||||
struct PHeap_Obj * owner;
|
||||
KrkValue value;
|
||||
PHeap * subheaps; /* Left pointer to first child, if any. */
|
||||
PHeap * next; /* Right pointer to next sibling, if any. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Heap comparator function.
|
||||
*
|
||||
* The heap is ostensibly a min-heap, but the comparison behavior is left
|
||||
* entirely to the user. A comparator function should return true if the
|
||||
* left (first) argument has priority (is less than) the right (second)
|
||||
* argument, and 0 otherwise. This comparison must be consistent or the
|
||||
* heap will not work correctly.
|
||||
*
|
||||
* Generally, this module only uses one comparison function: a wrapper that
|
||||
* calls a Kuroko callable. As Kuroko callables may hold their own state,
|
||||
* no facility was necessary to pass user data to the comparator - only
|
||||
* the left and right heap nodes to compare are given.
|
||||
*/
|
||||
typedef int (*pheap_comparator_func)(PHeap *, PHeap *);
|
||||
|
||||
/**
|
||||
* @brief meld - Combine two heaps.
|
||||
*
|
||||
* Combines two heaps and returns the result. The heaps are "destroyed" in the process.
|
||||
*
|
||||
* @param left One heap. Can be @c NULL for an empty heap.
|
||||
* @param right The other heap. Can be @c NULL for an empty heap.
|
||||
* @param comparator Function that should return true if @p left has priority (is less than) @p right.
|
||||
* @returns A pointer to the new root, which will be either of @p left or @p right.
|
||||
*/
|
||||
static PHeap * pheap_meld(PHeap * left, PHeap * right, pheap_comparator_func comparator) {
|
||||
/*
|
||||
* If either of the heaps is "empty" (represented by NULL),
|
||||
* then simply return the other one.
|
||||
*/
|
||||
if (!left) {
|
||||
return right;
|
||||
}
|
||||
if (!right) {
|
||||
return left;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, pull the 'smaller' of the two up and add the 'larger'
|
||||
* to the front of the subheap list of the smaller one. We use
|
||||
* intrusive lists within our Heap struct, so each Heap is also
|
||||
* a List node (with a `next` pointer).
|
||||
*/
|
||||
if (comparator(left, right)) {
|
||||
/* Turns `left` into Heap(left→value, right :: left→subheaps) */
|
||||
if (left->subheaps) {
|
||||
right->next = left->subheaps;
|
||||
}
|
||||
left->subheaps = right;
|
||||
return left;
|
||||
} else {
|
||||
/* Turns `right` into Heap(right→value, left :: right→subheaps) */
|
||||
if (right->subheaps) {
|
||||
left->next = right->subheaps;
|
||||
}
|
||||
right->subheaps = left;
|
||||
return right;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief merge_pairs - Perform left-to-right/right-to-left merge on lists of subheaps.
|
||||
*
|
||||
* The core of the heap.
|
||||
*
|
||||
* @param list List of pairs to merge.
|
||||
* @param comparator Comparator function as described in @c pheap_meld.
|
||||
* @returns the resulting heap.
|
||||
*/
|
||||
static PHeap * pheap_merge_pairs(PHeap * list, pheap_comparator_func comparator) {
|
||||
if (!list) {
|
||||
/* An empty list is represented by NULL, and yields an empty Heap,
|
||||
* which is also represented by NULL... */
|
||||
return NULL;
|
||||
} else if (list->next == NULL) {
|
||||
/* If a list entry doesn't have a next, it has a size of one,
|
||||
* and we can just return this heap directly. */
|
||||
return list;
|
||||
} else {
|
||||
/* Otherwise we meld the first two, then meld them with the result of
|
||||
* recursively melding the rest, which performs our left-right /
|
||||
* right-left two-stage merge. */
|
||||
PHeap * next = list->next;
|
||||
list->next = NULL;
|
||||
PHeap * rest = next->next;
|
||||
next->next = NULL;
|
||||
return pheap_meld(pheap_meld(list, next, comparator), pheap_merge_pairs(rest, comparator), comparator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief delete_min - Remove the 'smallest' value from the heap.
|
||||
*
|
||||
* Removes the root node of the heap, rebalancing the remainder
|
||||
* of the heap. Should only be used when the heap is not empty.
|
||||
*
|
||||
* @param heap Heap to remove the root of.
|
||||
* @param comparator Comparator function as described in @c pheap_meld.
|
||||
* @returns the resulting heap.
|
||||
*/
|
||||
static PHeap * pheap_delete_min(PHeap * heap, pheap_comparator_func comparator) {
|
||||
PHeap * subs = heap->subheaps;
|
||||
return pheap_merge_pairs(subs, comparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief visit_heap - Call a user function for every node in the heap.
|
||||
*
|
||||
* The function is called before recursing.
|
||||
*
|
||||
* @param heap Heap to walk.
|
||||
* @param func Function to call.
|
||||
* @param extra User data to pass to the function.
|
||||
*/
|
||||
static void pheap_visit_heap(PHeap * heap, void (*func)(PHeap *, void*), void* extra) {
|
||||
if (!heap) return;
|
||||
func(heap, extra);
|
||||
pheap_visit_heap(heap->subheaps, func, extra);
|
||||
pheap_visit_heap(heap->next, func, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief visit_heap_after - Call a user function for every node in the heap.
|
||||
*
|
||||
* The function is called after recursing, so this is suitable for freeing the
|
||||
* entirety of a heap.
|
||||
*
|
||||
* @param heap Heap to walk.
|
||||
* @param func Function to call.
|
||||
* @param extra User data to pass to the function.
|
||||
*/
|
||||
static void pheap_visit_heap_after(PHeap * heap, void (*func)(PHeap *, void*), void* extra) {
|
||||
if (!heap) return;
|
||||
pheap_visit_heap_after(heap->subheaps, func, extra);
|
||||
pheap_visit_heap_after(heap->next, func, extra);
|
||||
func(heap, extra);
|
||||
}
|
||||
|
||||
struct PHeap_Obj {
|
||||
KrkInstance inst;
|
||||
KrkValue comparator;
|
||||
PHeap * heap;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
#define IS_PHeap(o) (krk_isInstanceOf(o,PHeapClass))
|
||||
#define AS_PHeap(o) ((struct PHeap_Obj*)AS_OBJECT(o))
|
||||
#define CURRENT_CTYPE struct PHeap_Obj *
|
||||
#define CURRENT_NAME self
|
||||
|
||||
KRK_Method(PHeap,__init__) {
|
||||
KrkValue comparator;
|
||||
if (!krk_parseArgs(".V:PHeap", (const char*[]){"comp"}, &comparator)) return NONE_VAL();
|
||||
self->comparator = comparator;
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
static int run_comparator(PHeap * left, PHeap * right) {
|
||||
assert(left->owner == right->owner);
|
||||
krk_push(left->owner->comparator);
|
||||
krk_push(left->value);
|
||||
krk_push(right->value);
|
||||
KrkValue result = krk_callStack(2);
|
||||
if (!IS_BOOLEAN(result)) return 0;
|
||||
return AS_BOOLEAN(result);
|
||||
}
|
||||
|
||||
KRK_Method(PHeap,insert) {
|
||||
KrkValue value;
|
||||
if (!krk_parseArgs(".V",(const char*[]){"value"}, &value)) return NONE_VAL();
|
||||
struct PHeap * node = calloc(sizeof(struct PHeap), 1);
|
||||
node->owner = self;
|
||||
node->value = value;
|
||||
self->heap = pheap_meld(self->heap, node, run_comparator);
|
||||
self->count += 1;
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(PHeap,peek) {
|
||||
if (self->heap) return self->heap->value;
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(PHeap,pop) {
|
||||
PHeap * old = self->heap;
|
||||
if (!old) return krk_runtimeError(vm.exceptions->indexError, "pop from empty heap");
|
||||
self->heap = pheap_delete_min(self->heap, run_comparator);
|
||||
self->count -= 1;
|
||||
KrkValue out = old->value;
|
||||
free(old);
|
||||
return out;
|
||||
}
|
||||
|
||||
KRK_Method(PHeap,__bool__) {
|
||||
return BOOLEAN_VAL(self->heap != NULL);
|
||||
}
|
||||
|
||||
KRK_Method(PHeap,__len__) {
|
||||
return INTEGER_VAL(self->count);
|
||||
}
|
||||
|
||||
static void run_visitor(PHeap * heap, void * visitor) {
|
||||
krk_push(*(KrkValue*)visitor);
|
||||
krk_push(heap->value);
|
||||
krk_callStack(1);
|
||||
}
|
||||
|
||||
KRK_Method(PHeap,visit) {
|
||||
KrkValue func;
|
||||
int after = 0;
|
||||
if (!krk_parseArgs(".V|p",(const char*[]){"func","after"},
|
||||
&func, &after)) return NONE_VAL();
|
||||
|
||||
(after ? pheap_visit_heap_after : pheap_visit_heap)(self->heap, run_visitor, &func);
|
||||
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
static void _scan_one(PHeap * heap, void * unused) {
|
||||
krk_markValue(heap->value);
|
||||
}
|
||||
|
||||
static void _pheap_scan(KrkInstance * _self) {
|
||||
struct PHeap_Obj * self = (void*)_self;
|
||||
krk_markValue(self->comparator);
|
||||
pheap_visit_heap(self->heap, _scan_one, NULL);
|
||||
}
|
||||
|
||||
static void _free_one(PHeap * heap, void * unused) {
|
||||
free(heap);
|
||||
}
|
||||
|
||||
static void _pheap_sweep(KrkInstance * _self) {
|
||||
struct PHeap_Obj * self = (void*)_self;
|
||||
pheap_visit_heap_after(self->heap,_free_one, NULL);
|
||||
}
|
||||
|
||||
KRK_Method(PHeap,comp) {
|
||||
return self->comparator;
|
||||
}
|
||||
|
||||
KRK_Module(_pheap) {
|
||||
KRK_DOC(module, "Pairing heap with simple insert and pop-min operations.");
|
||||
|
||||
KrkClass * PHeap = krk_makeClass(module, &PHeapClass, "PHeap", vm.baseClasses->objectClass);
|
||||
KRK_DOC(PHeap,"Pairing heap with simple insert and pop-min operations.");
|
||||
PHeap->allocSize = sizeof(struct PHeap_Obj);
|
||||
PHeap->_ongcscan = _pheap_scan;
|
||||
PHeap->_ongcsweep = _pheap_sweep;
|
||||
|
||||
KRK_DOC(BIND_METHOD(PHeap,__init__),
|
||||
"@arguments comp\n\n"
|
||||
"Create a new pairing heap governed by the given comparator function.");
|
||||
KRK_DOC(BIND_METHOD(PHeap,insert),
|
||||
"@arguments value\n\n"
|
||||
"Insert a new element into the heap.");
|
||||
KRK_DOC(BIND_METHOD(PHeap,peek),
|
||||
"Retrieve the root (smallest) element of the heap, or None if it is empty.");
|
||||
KRK_DOC(BIND_METHOD(PHeap,pop),
|
||||
"Remove and return the root (smallest) element of the heap. If the heap is empty, IndexError is raised.");
|
||||
BIND_METHOD(PHeap,__bool__);
|
||||
BIND_METHOD(PHeap,__len__);
|
||||
KRK_DOC(BIND_METHOD(PHeap,visit),
|
||||
"@arguments func,after=False\n\n"
|
||||
"Call a function for each element of the heap.");
|
||||
BIND_PROP(PHeap,comp);
|
||||
krk_finalizeClass(PHeapClass);
|
||||
}
|
376
src/modules/module_dis.c
Normal file
376
src/modules/module_dis.c
Normal file
@ -0,0 +1,376 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <kuroko/debug.h>
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/util.h>
|
||||
#include <kuroko/compiler.h>
|
||||
|
||||
#include "../private.h"
|
||||
#include "../opcode_enum.h"
|
||||
|
||||
#ifndef KRK_DISABLE_DEBUG
|
||||
|
||||
KRK_Function(enablebreakpoint) {
|
||||
int breakIndex;
|
||||
if (!krk_parseArgs("i",(const char*[]){"breakpoint"}, &breakIndex)) return NONE_VAL();
|
||||
if (krk_debug_enableBreakpoint(breakIndex))
|
||||
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Function(disablebreakpoint) {
|
||||
int breakIndex;
|
||||
if (!krk_parseArgs("i",(const char*[]){"breakpoint"}, &breakIndex)) return NONE_VAL();
|
||||
if (krk_debug_disableBreakpoint(breakIndex))
|
||||
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Function(delbreakpoint) {
|
||||
int breakIndex;
|
||||
if (!krk_parseArgs("i",(const char*[]){"breakpoint"}, &breakIndex)) return NONE_VAL();
|
||||
if (krk_debug_removeBreakpoint(breakIndex))
|
||||
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Function(addbreakpoint) {
|
||||
KrkValue func;
|
||||
int lineNo;
|
||||
int flags = KRK_BREAKPOINT_NORMAL;
|
||||
if (!krk_parseArgs("Vi|i",(const char*[]){"func","lineno","flags"}, &func, &lineNo, &flags)) return NONE_VAL();
|
||||
|
||||
int result;
|
||||
if (IS_STRING(func)) {
|
||||
result = krk_debug_addBreakpointFileLine(AS_STRING(func), lineNo, flags);
|
||||
} else {
|
||||
KrkCodeObject * target = NULL;
|
||||
if (IS_CLOSURE(func)) {
|
||||
target = AS_CLOSURE(func)->function;
|
||||
} else if (IS_BOUND_METHOD(func) && IS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(func)->method))) {
|
||||
target = AS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(func)->method))->function;
|
||||
} else if (IS_codeobject(func)) {
|
||||
target = AS_codeobject(func);
|
||||
} else {
|
||||
return TYPE_ERROR(function or method or filename,func);
|
||||
}
|
||||
/* Figure out what instruction this should be on */
|
||||
size_t last = 0;
|
||||
for (size_t i = 0; i < target->chunk.linesCount; ++i) {
|
||||
if (target->chunk.lines[i].line > (size_t)lineNo) break;
|
||||
if (target->chunk.lines[i].line == (size_t)lineNo) {
|
||||
last = target->chunk.lines[i].startOffset;
|
||||
break;
|
||||
}
|
||||
last = target->chunk.lines[i].startOffset;
|
||||
}
|
||||
result = krk_debug_addBreakpointCodeOffset(target,last,flags);
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
return krk_runtimeError(vm.exceptions->baseException, "Could not add breakpoint.");
|
||||
|
||||
return INTEGER_VAL(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dis.dis(object)
|
||||
*/
|
||||
KRK_Function(dis) {
|
||||
KrkValue funcVal;
|
||||
if (!krk_parseArgs("V",(const char*[]){"func"},&funcVal)) return NONE_VAL();
|
||||
|
||||
if (IS_CLOSURE(funcVal)) {
|
||||
KrkCodeObject * func = AS_CLOSURE(funcVal)->function;
|
||||
krk_disassembleCodeObject(stdout, func, func->name ? func->name->chars : "<unnamed>");
|
||||
} else if (IS_codeobject(funcVal)) {
|
||||
krk_disassembleCodeObject(stdout, AS_codeobject(funcVal), AS_codeobject(funcVal)->name ? AS_codeobject(funcVal)->name->chars : "<unnamed>");
|
||||
} else if (IS_BOUND_METHOD(funcVal)) {
|
||||
if (AS_BOUND_METHOD(funcVal)->method->type == KRK_OBJ_CLOSURE) {
|
||||
KrkCodeObject * func = ((KrkClosure*)AS_BOUND_METHOD(funcVal)->method)->function;
|
||||
const char * methodName = func->name ? func->name->chars : "<unnamed>";
|
||||
const char * typeName = IS_CLASS(AS_BOUND_METHOD(funcVal)->receiver) ? AS_CLASS(AS_BOUND_METHOD(funcVal)->receiver)->name->chars : krk_typeName(AS_BOUND_METHOD(funcVal)->receiver);
|
||||
size_t allocSize = strlen(methodName) + strlen(typeName) + 2;
|
||||
char * tmp = malloc(allocSize);
|
||||
snprintf(tmp, allocSize, "%s.%s", typeName, methodName);
|
||||
krk_disassembleCodeObject(stdout, func, tmp);
|
||||
free(tmp);
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%T'", AS_BOUND_METHOD(funcVal)->receiver);
|
||||
}
|
||||
} else if (IS_CLASS(funcVal)) {
|
||||
KrkValue code;
|
||||
if (krk_tableGet(&AS_CLASS(funcVal)->methods, vm.specialMethodNames[METHOD_FUNC], &code) && IS_CLOSURE(code)) {
|
||||
KrkCodeObject * func = AS_CLOSURE(code)->function;
|
||||
krk_disassembleCodeObject(stdout, func, AS_CLASS(funcVal)->name->chars);
|
||||
}
|
||||
/* TODO Methods! */
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%T'", funcVal);
|
||||
}
|
||||
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Function(build) {
|
||||
char * code;
|
||||
char * fileName = "<source>";
|
||||
if (!krk_parseArgs("s|s", (const char*[]){"code","filename"}, &code, &fileName)) return NONE_VAL();
|
||||
|
||||
/* Unset module */
|
||||
krk_push(OBJECT_VAL(krk_currentThread.module));
|
||||
KrkInstance * module = krk_currentThread.module;
|
||||
krk_currentThread.module = NULL;
|
||||
KrkCodeObject * c = krk_compile(code,fileName);
|
||||
krk_currentThread.module = module;
|
||||
krk_pop();
|
||||
if (c) return OBJECT_VAL(c);
|
||||
else return NONE_VAL();
|
||||
}
|
||||
|
||||
#define NOOP (void)0
|
||||
#define SIMPLE(opc) case opc: size = 1; break;
|
||||
#define CONSTANT(opc,more) case opc: { constant = chunk->code[offset + 1]; size = 2; more; break; } \
|
||||
case opc ## _LONG: { constant = (chunk->code[offset + 1] << 16) | \
|
||||
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
|
||||
#define OPERAND(opc,more) case opc: { operand = chunk->code[offset + 1]; size = 2; more; break; } \
|
||||
case opc ## _LONG: { operand = (chunk->code[offset + 1] << 16) | \
|
||||
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
|
||||
#define JUMP(opc,sign) case opc: { jump = 0 sign ((chunk->code[offset + 1] << 8) | (chunk->code[offset + 2])); \
|
||||
size = 3; break; }
|
||||
#define COMPLICATED(opc,more) case opc: size = 1; more; break;
|
||||
#define OVERLONG_JUMP_MORE size = 3; jump = (chunk->code[offset + 1] << 8) | (chunk->code[offset + 2])
|
||||
#define CLOSURE_MORE \
|
||||
KrkCodeObject * function = AS_codeobject(chunk->constants.values[constant]); \
|
||||
size_t baseOffset = offset; \
|
||||
for (size_t j = 0; j < function->upvalueCount; ++j) { \
|
||||
int isLocal = chunk->code[baseOffset++ + size]; \
|
||||
baseOffset++; \
|
||||
if (isLocal & 2) { \
|
||||
baseOffset += 2; \
|
||||
} \
|
||||
} \
|
||||
size += baseOffset - offset;
|
||||
#define EXPAND_ARGS_MORE
|
||||
#define FORMAT_VALUE_MORE
|
||||
#define LOCAL_MORE local = operand;
|
||||
static KrkValue _examineInternal(KrkCodeObject* func) {
|
||||
KrkValue output = krk_list_of(0,NULL,0);
|
||||
krk_push(output);
|
||||
|
||||
KrkChunk * chunk = &func->chunk;
|
||||
size_t offset = 0;
|
||||
while (offset < chunk->count) {
|
||||
uint8_t opcode = chunk->code[offset];
|
||||
size_t size = 0;
|
||||
ssize_t constant = -1;
|
||||
ssize_t jump = 0;
|
||||
ssize_t operand = -1;
|
||||
ssize_t local = -1;
|
||||
switch (opcode) {
|
||||
#include "opcodes.h"
|
||||
}
|
||||
|
||||
KrkTuple * newTuple = krk_newTuple(3);
|
||||
krk_push(OBJECT_VAL(newTuple));
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(opcode);
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(size);
|
||||
if (constant != -1) {
|
||||
newTuple->values.values[newTuple->values.count++] = chunk->constants.values[constant];
|
||||
} else if (jump != 0) {
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(jump);
|
||||
} else if (local != -1) {
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand); /* Just in case */
|
||||
for (size_t i = 0; i < func->localNameCount; ++i) {
|
||||
if (func->localNames[i].id == (size_t)local && func->localNames[i].birthday <= offset && func->localNames[i].deathday >= offset) {
|
||||
newTuple->values.values[newTuple->values.count-1] = OBJECT_VAL(func->localNames[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (operand != -1) {
|
||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand);
|
||||
} else {
|
||||
newTuple->values.values[newTuple->values.count++] = NONE_VAL();
|
||||
}
|
||||
krk_writeValueArray(AS_LIST(output), krk_peek(0));
|
||||
krk_pop();
|
||||
|
||||
if (size == 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
KRK_Function(examine) {
|
||||
KrkCodeObject * func;
|
||||
if (!krk_parseArgs("O!",(const char*[]){"func"}, KRK_BASE_CLASS(codeobject), &func)) return NONE_VAL();
|
||||
return _examineInternal(func);
|
||||
}
|
||||
|
||||
#undef SIMPLE
|
||||
#undef OPERANDB
|
||||
#undef OPERAND
|
||||
#undef CONSTANT
|
||||
#undef JUMP
|
||||
#undef COMPLICATED
|
||||
#undef OVERLONG_JUMP_MORE
|
||||
#undef CLOSURE_MORE
|
||||
#undef LOCAL_MORE
|
||||
#undef EXPAND_ARGS_MORE
|
||||
#undef FORMAT_VALUE_MORE
|
||||
|
||||
KRK_Function(ip_to_expression) {
|
||||
KrkValue func;
|
||||
size_t ip;
|
||||
|
||||
if (!krk_parseArgs("VN",(const char*[]){"func","ip"}, &func, &ip)) return NONE_VAL();
|
||||
|
||||
KrkCodeObject * actual;
|
||||
|
||||
if (IS_CLOSURE(func)) actual = AS_CLOSURE(func)->function;
|
||||
else if (IS_codeobject(func)) actual = AS_codeobject(func);
|
||||
else if (IS_BOUND_METHOD(func) && IS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(func)->method))) actual = ((KrkClosure*)AS_BOUND_METHOD(func)->method)->function;
|
||||
else return krk_runtimeError(vm.exceptions->typeError, "func must be a managed function, method, or codeobject, not '%T'", func);
|
||||
|
||||
int lineNo = krk_lineNumber(&actual->chunk, ip);
|
||||
uint8_t start, midStart, midEnd, end;
|
||||
|
||||
if (krk_debug_expressionUnderline(actual, &start, &midStart, &midEnd, &end, ip)) {
|
||||
KrkTuple * out = krk_newTuple(5);
|
||||
krk_push(OBJECT_VAL(out));
|
||||
|
||||
out->values.values[out->values.count++] = INTEGER_VAL(lineNo);
|
||||
out->values.values[out->values.count++] = INTEGER_VAL(start);
|
||||
out->values.values[out->values.count++] = INTEGER_VAL(midStart);
|
||||
out->values.values[out->values.count++] = INTEGER_VAL(midEnd);
|
||||
out->values.values[out->values.count++] = INTEGER_VAL(end);
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
KRK_Module(dis) {
|
||||
#ifndef KRK_DISABLE_DEBUG
|
||||
KRK_DOC(module,
|
||||
"@brief Provides tools for disassembling bytecode.\n\n"
|
||||
"### Code Disassembly in Kuroko\n\n"
|
||||
"The @c dis module contains functions for dealing with _code objects_ which "
|
||||
"represent the compiled bytecode of a Kuroko function. The bytecode compilation "
|
||||
"process is entirely static and bytecode analysis can be performed without calling "
|
||||
"into the VM to run dynamic code.\n\n"
|
||||
"### Debugger Breakpoints\n\n"
|
||||
"Kuroko interpreters can provide a debugger hook through the C API's "
|
||||
"@ref krk_debug_registerCallback() function. Breakpoints can be managed both "
|
||||
"from the C API and from this module's @ref addbreakpoint, @ref delbreakpoint, "
|
||||
"@ref enablebreakpoint, and @ref disablebreakpoint methods."
|
||||
);
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, dis),
|
||||
"@brief Disassemble an object.\n"
|
||||
"@arguments obj\n\n"
|
||||
"Dumps a disassembly of the bytecode in the code object associated with @p obj. "
|
||||
"If @p obj can not be disassembled, a @ref TypeError is raised.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, build),
|
||||
"@brief Compile a string to a code object.\n"
|
||||
"@arguments code\n\n"
|
||||
"Compiles the string @p code and returns a code object. If a syntax "
|
||||
"error is encountered, it will be raised.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, examine),
|
||||
"@brief Convert a code object to a list of instructions.\n"
|
||||
"@arguments func\n\n"
|
||||
"Examines the code object @p func and returns a list representation of its instructions. "
|
||||
"Each instruction entry is a tuple of the opcode, total instruction size in bytes, and "
|
||||
"the operand of the argument, either as an integer for jump offsets, the actual value for "
|
||||
"constant operands, or the name of a local or global variable if available.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, addbreakpoint),
|
||||
"@brief Attach a breakpoint to a code object.\n"
|
||||
"@arguments func, line\n\n"
|
||||
"@p func may be a filename string, or a function, method, or code object. Returns "
|
||||
"the new breakpoint index, or raises @ref Exception if a breakpoint code not be added.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, delbreakpoint),
|
||||
"@brief Delete a breakpoint.\n"
|
||||
"@arguments handle\n\n"
|
||||
"Delete the breakpoint specified by @p handle, disabling it if it was enabled. "
|
||||
"May raise @ref IndexError if @p handle is not a valid breakpoint handle.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, enablebreakpoint),
|
||||
"@brief Enable a breakpoint.\n"
|
||||
"@arguments handle\n\n"
|
||||
"Enable the breakpoint specified by @p handle. May raise @ref IndexError if "
|
||||
"@p handle is not a valid breakpoint handle.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, disablebreakpoint),
|
||||
"@brief Disable a breakpoint.\n"
|
||||
"@arguments handle\n\n"
|
||||
"Disable the breakpoint specified by @p handle. May raise @ref IndexError if "
|
||||
"@p handle is not a valid breakpoint handle.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module, ip_to_expression),
|
||||
"@brief Map an IP in a codeobject or function to an expression span.\n"
|
||||
"@arguments func,ip\n\n"
|
||||
"For various reasons, the instruction pointer @p ip must be the last byte of an opcode.");
|
||||
|
||||
krk_attachNamedValue(&module->fields, "BREAKPOINT_ONCE", INTEGER_VAL(KRK_BREAKPOINT_ONCE));
|
||||
krk_attachNamedValue(&module->fields, "BREAKPOINT_REPEAT", INTEGER_VAL(KRK_BREAKPOINT_REPEAT));
|
||||
|
||||
#define OPCODE(opc) krk_attachNamedValue(&module->fields, #opc, INTEGER_VAL(opc));
|
||||
#define SIMPLE(opc) OPCODE(opc)
|
||||
#define CONSTANT(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
|
||||
#define OPERAND(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
|
||||
#define JUMP(opc,sign) OPCODE(opc)
|
||||
#define COMPLICATED(opc,more) OPCODE(opc)
|
||||
#include "opcodes.h"
|
||||
#undef SIMPLE
|
||||
#undef OPERANDB
|
||||
#undef OPERAND
|
||||
#undef CONSTANT
|
||||
#undef JUMP
|
||||
#undef COMPLICATED
|
||||
|
||||
if (runAs && !strcmp(runAs->chars,"__main__")) {
|
||||
/* Force `dis` into the module table early */
|
||||
krk_attachNamedObject(&vm.modules, "dis", (KrkObj*)module);
|
||||
/* Start executing additional code */
|
||||
krk_startModule("_dis");
|
||||
krk_interpret(
|
||||
"import dis\n"
|
||||
"def disrec(code, seen):\n"
|
||||
" let next = [code]\n"
|
||||
" while next:\n"
|
||||
" let co = next[0]\n"
|
||||
" next = next[1:]\n"
|
||||
" dis.dis(co)\n"
|
||||
" for inst,size,operand in dis.examine(co):\n"
|
||||
" if isinstance(operand,codeobject) and operand not in seen and operand not in next:\n"
|
||||
" next.append(operand)\n"
|
||||
" if next:\n"
|
||||
" print()\n"
|
||||
"import kuroko\n"
|
||||
"if (len(kuroko.argv) < 2):\n"
|
||||
" print(\"Usage: kuroko -m dis FILE\")\n"
|
||||
" return 1\n"
|
||||
"import fileio\n"
|
||||
"for file in kuroko.argv[1:]:\n"
|
||||
" with fileio.open(file,'r') as f:\n"
|
||||
" let result = dis.build(f.read(), file)\n"
|
||||
" disrec(result,set())\n",
|
||||
"_dis"
|
||||
);
|
||||
}
|
||||
#else
|
||||
krk_runtimeError(vm.exceptions->notImplementedError, "debugger support is disabled");
|
||||
#endif
|
||||
}
|
@ -14,6 +14,11 @@
|
||||
#include <kuroko/memory.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
|
||||
static KrkClass * fileio_File;
|
||||
static KrkClass * fileio_BinaryFile;
|
||||
static KrkClass * fileio_Directory;
|
||||
|
||||
/**
|
||||
* @brief Object for a C `FILE*` stream.
|
||||
* @extends KrkInstance
|
||||
@ -24,10 +29,10 @@ struct File {
|
||||
int unowned;
|
||||
};
|
||||
|
||||
#define IS_File(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(File)))
|
||||
#define IS_File(o) (krk_isInstanceOf(o, fileio_File))
|
||||
#define AS_File(o) ((struct File*)AS_OBJECT(o))
|
||||
|
||||
#define IS_BinaryFile(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(BinaryFile)))
|
||||
#define IS_BinaryFile(o) (krk_isInstanceOf(o, fileio_BinaryFile))
|
||||
#define AS_BinaryFile(o) ((struct File*)AS_OBJECT(o))
|
||||
|
||||
/**
|
||||
@ -39,7 +44,7 @@ struct Directory {
|
||||
DIR * dirPtr;
|
||||
};
|
||||
|
||||
#define IS_Directory(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(Directory)))
|
||||
#define IS_Directory(o) (krk_isInstanceOf(o, fileio_Directory))
|
||||
#define AS_Directory(o) ((struct Directory*)AS_OBJECT(o))
|
||||
|
||||
#define CURRENT_CTYPE struct File *
|
||||
@ -77,7 +82,7 @@ KRK_Function(open) {
|
||||
if (!file) return krk_runtimeError(vm.exceptions->ioError, "open: failed to open file; system returned: %s", strerror(errno));
|
||||
|
||||
/* Now let's build an object to hold it */
|
||||
KrkInstance * fileObject = krk_newInstance(isBinary ? KRK_BASE_CLASS(BinaryFile) : KRK_BASE_CLASS(File));
|
||||
KrkInstance * fileObject = krk_newInstance(isBinary ? fileio_BinaryFile : fileio_File);
|
||||
krk_push(OBJECT_VAL(fileObject));
|
||||
|
||||
/* Let's put the filename in there somewhere... */
|
||||
@ -93,7 +98,7 @@ KRK_Function(open) {
|
||||
|
||||
#define BLOCK_SIZE 1024
|
||||
|
||||
KRK_Method(File,__str__) {
|
||||
KRK_Method(File,__repr__) {
|
||||
METHOD_TAKES_NONE();
|
||||
KrkValue filename;
|
||||
KrkValue modestr;
|
||||
@ -259,7 +264,7 @@ KRK_Method(File,__exit__) {
|
||||
}
|
||||
|
||||
static void makeFileInstance(KrkInstance * module, const char name[], FILE * file, const char mode[]) {
|
||||
KrkInstance * fileObject = krk_newInstance(KRK_BASE_CLASS(File));
|
||||
KrkInstance * fileObject = krk_newInstance(fileio_File);
|
||||
krk_push(OBJECT_VAL(fileObject));
|
||||
KrkValue filename = OBJECT_VAL(krk_copyString(name,strlen(name)));
|
||||
krk_push(filename);
|
||||
@ -433,7 +438,7 @@ KRK_Function(opendir) {
|
||||
DIR * dir = opendir(path->chars);
|
||||
if (!dir) return krk_runtimeError(vm.exceptions->ioError, "opendir: %s", strerror(errno));
|
||||
|
||||
struct Directory * dirObj = (void *)krk_newInstance(KRK_BASE_CLASS(Directory));
|
||||
struct Directory * dirObj = (void *)krk_newInstance(fileio_Directory);
|
||||
krk_push(OBJECT_VAL(dirObj));
|
||||
|
||||
krk_attachNamedValue(&dirObj->inst.fields, "path", OBJECT_VAL(path));
|
||||
@ -489,11 +494,7 @@ KRK_Method(Directory,__exit__) {
|
||||
return FUNC_NAME(Directory,close)(1,argv,0);
|
||||
}
|
||||
|
||||
void krk_module_init_fileio(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_attachNamedObject(&vm.modules, "fileio", (KrkObj*)module);
|
||||
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("fileio"));
|
||||
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
|
||||
KRK_Module(fileio) {
|
||||
KRK_DOC(module,
|
||||
"@brief Provides access to C <stdio> buffered file I/O functions.\n\n"
|
||||
"The @c fileio module provides classes and functions for reading "
|
||||
@ -502,7 +503,7 @@ void krk_module_init_fileio(void) {
|
||||
);
|
||||
|
||||
/* Define a class to represent files. (Should this be a helper method?) */
|
||||
KrkClass * File = krk_makeClass(module, &KRK_BASE_CLASS(File), "File", KRK_BASE_CLASS(object));
|
||||
KrkClass * File = krk_makeClass(module, &fileio_File, "File", KRK_BASE_CLASS(object));
|
||||
KRK_DOC(File,"Interface to a buffered file stream.");
|
||||
File->allocSize = sizeof(struct File);
|
||||
File->_ongcsweep = _file_sweep;
|
||||
@ -519,15 +520,14 @@ void krk_module_init_fileio(void) {
|
||||
"Writes the contents of @p data to the stream.");
|
||||
KRK_DOC(BIND_METHOD(File,close), "@brief Close the stream and flush any remaining buffered writes.");
|
||||
KRK_DOC(BIND_METHOD(File,flush), "@brief Flush unbuffered writes to the stream.");
|
||||
BIND_METHOD(File,__str__);
|
||||
BIND_METHOD(File,__repr__);
|
||||
KRK_DOC(BIND_METHOD(File,__init__), "@bsnote{%File objects can not be initialized using this constructor. "
|
||||
"Use the <a class=\"el\" href=\"#open\">open()</a> function instead.}");
|
||||
BIND_METHOD(File,__enter__);
|
||||
BIND_METHOD(File,__exit__);
|
||||
krk_defineNative(&File->methods, "__repr__", FUNC_NAME(File,__str__));
|
||||
krk_finalizeClass(File);
|
||||
|
||||
KrkClass * BinaryFile = krk_makeClass(module, &KRK_BASE_CLASS(BinaryFile), "BinaryFile", File);
|
||||
KrkClass * BinaryFile = krk_makeClass(module, &fileio_BinaryFile, "BinaryFile", File);
|
||||
KRK_DOC(BinaryFile,
|
||||
"Equivalent to @ref File but using @ref bytes instead of string @ref str."
|
||||
);
|
||||
@ -537,7 +537,7 @@ void krk_module_init_fileio(void) {
|
||||
BIND_METHOD(BinaryFile,write);
|
||||
krk_finalizeClass(BinaryFile);
|
||||
|
||||
KrkClass * Directory = krk_makeClass(module, &KRK_BASE_CLASS(Directory), "Directory", KRK_BASE_CLASS(object));
|
||||
KrkClass * Directory = krk_makeClass(module, &fileio_Directory, "Directory", KRK_BASE_CLASS(object));
|
||||
KRK_DOC(Directory,
|
||||
"Represents an opened file system directory."
|
||||
);
|
31
src/modules/module_gc.c
Normal file
31
src/modules/module_gc.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
KRK_Function(collect) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
if (&krk_currentThread != vm.threads) return krk_runtimeError(vm.exceptions->valueError, "only the main thread can do that");
|
||||
return INTEGER_VAL(krk_collectGarbage());
|
||||
}
|
||||
|
||||
KRK_Function(pause) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
vm.globalFlags |= (KRK_GLOBAL_GC_PAUSED);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Function(resume) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
vm.globalFlags &= ~(KRK_GLOBAL_GC_PAUSED);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Module(gc) {
|
||||
KRK_DOC(module, "@brief Namespace containing methods for controlling the garbage collector.");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module,collect),
|
||||
"@brief Triggers one cycle of garbage collection.");
|
||||
KRK_DOC(BIND_FUNC(module,pause),
|
||||
"@brief Disables automatic garbage collection until @ref resume is called.");
|
||||
KRK_DOC(BIND_FUNC(module,resume),
|
||||
"@brief Re-enable automatic garbage collection after it was stopped by @ref pause ");
|
||||
}
|
99
src/modules/module_locale.c
Normal file
99
src/modules/module_locale.c
Normal file
@ -0,0 +1,99 @@
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
KRK_Function(setlocale) {
|
||||
int category;
|
||||
const char * locale = NULL;
|
||||
if (!krk_parseArgs("i|z",(const char*[]){"category","locale"}, &category, &locale)) return NONE_VAL();
|
||||
char * result = setlocale(category, locale);
|
||||
if (!result) {
|
||||
return krk_runtimeError(vm.exceptions->valueError, "unsupported locale setting or query failed");
|
||||
}
|
||||
return OBJECT_VAL(krk_copyString(result,strlen(result)));
|
||||
}
|
||||
|
||||
static void do_grouping(KrkValue result, const char * keyname, const char * grouping) {
|
||||
KrkValue out = krk_list_of(0,NULL,0);
|
||||
krk_push(out);
|
||||
|
||||
const char * c = grouping;
|
||||
|
||||
/* If there is nothing here, return an empty list, otherwise return all
|
||||
* entries including either a terminating NUL or a terminating CHAR_MAX */
|
||||
if (*c) {
|
||||
do {
|
||||
krk_writeValueArray(AS_LIST(out), INTEGER_VAL(*c));
|
||||
if (!*c || *c == CHAR_MAX) break;
|
||||
c++;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
krk_attachNamedValue(AS_DICT(result), keyname, out);
|
||||
krk_pop();
|
||||
}
|
||||
|
||||
KRK_Function(localeconv) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
|
||||
struct lconv * lc = localeconv();
|
||||
|
||||
/* localeconv is defined to never fail... */
|
||||
|
||||
KrkValue result = krk_dict_of(0,NULL,0);
|
||||
krk_push(result);
|
||||
|
||||
#define DO_DICT_STR(key) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)krk_copyString(lc-> key, strlen(lc-> key)))
|
||||
#define DO_DICT_INT(key) krk_attachNamedValue(AS_DICT(result), #key, INTEGER_VAL(lc-> key))
|
||||
|
||||
DO_DICT_STR(decimal_point);
|
||||
DO_DICT_STR(thousands_sep);
|
||||
DO_DICT_STR(int_curr_symbol);
|
||||
DO_DICT_STR(currency_symbol);
|
||||
DO_DICT_STR(mon_decimal_point);
|
||||
DO_DICT_STR(mon_thousands_sep);
|
||||
DO_DICT_STR(positive_sign);
|
||||
DO_DICT_STR(negative_sign);
|
||||
|
||||
DO_DICT_INT(int_frac_digits);
|
||||
DO_DICT_INT(frac_digits);
|
||||
DO_DICT_INT(p_cs_precedes);
|
||||
DO_DICT_INT(p_sep_by_space);
|
||||
DO_DICT_INT(n_cs_precedes);
|
||||
DO_DICT_INT(n_sep_by_space);
|
||||
DO_DICT_INT(p_sign_posn);
|
||||
DO_DICT_INT(n_sign_posn);
|
||||
|
||||
/* 'grouping' and 'mon_grouping' aren't real strings */
|
||||
do_grouping(result, "grouping", lc->grouping);
|
||||
do_grouping(result, "mon_grouping", lc->mon_grouping);
|
||||
|
||||
#undef DO_DICT_STR
|
||||
#undef DO_DICT_INT
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
KRK_Module(locale) {
|
||||
KRK_DOC(module, "@brief Bindings for C locale functions");
|
||||
|
||||
KRK_DOC(BIND_FUNC(module,setlocale),
|
||||
"@brief Set or query the C locale\n"
|
||||
"@arguments category,locale=None\n\n"
|
||||
"Set the locale used by various C functions.");
|
||||
BIND_FUNC(module,localeconv);
|
||||
|
||||
#define DO_INT(name) krk_attachNamedValue(&module->fields, #name, INTEGER_VAL(name))
|
||||
DO_INT(LC_ALL);
|
||||
DO_INT(LC_COLLATE);
|
||||
DO_INT(LC_CTYPE);
|
||||
DO_INT(LC_MONETARY);
|
||||
DO_INT(LC_NUMERIC);
|
||||
DO_INT(LC_TIME);
|
||||
/* LC_MESSAGES ? */
|
||||
DO_INT(CHAR_MAX); /* Needed to understand grouping */
|
||||
#undef DO_INT
|
||||
|
||||
}
|
@ -38,11 +38,13 @@
|
||||
return NONE_VAL(); \
|
||||
}
|
||||
|
||||
extern KrkValue krk_int_from_float(double val);
|
||||
|
||||
#define MATH_DELEGATE(func) \
|
||||
static KrkValue _math_ ## func(int argc, const KrkValue argv[], int hasKw) { \
|
||||
ONE_ARGUMENT(func) \
|
||||
if (IS_FLOATING(argv[0])) { \
|
||||
return INTEGER_VAL(func(AS_FLOATING(argv[0]))); \
|
||||
return krk_int_from_float(func(AS_FLOATING(argv[0]))); \
|
||||
} else if (IS_INTEGER(argv[0])) { \
|
||||
return argv[0]; /* no op */ \
|
||||
} else { \
|
||||
@ -146,10 +148,7 @@ MATH_IS(isnan)
|
||||
|
||||
#define bind(name) krk_defineNative(&module->fields, #name, _math_ ## name)
|
||||
|
||||
KrkValue krk_module_onload_math(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_push(OBJECT_VAL(module));
|
||||
|
||||
KRK_Module(math) {
|
||||
KRK_DOC(module, "@brief Provides access to floating-point mathematical functions from the system `libm`.");
|
||||
KRK_DOC(bind(ceil),
|
||||
"@brief Returns the smallest integer value not less than the input.\n"
|
||||
@ -269,7 +268,4 @@ KrkValue krk_module_onload_math(void) {
|
||||
krk_attachNamedValue(&module->fields, "e", FLOATING_VAL(M_E));
|
||||
krk_attachNamedValue(&module->fields, "inf", FLOATING_VAL(INFINITY));
|
||||
krk_attachNamedValue(&module->fields, "nan", FLOATING_VAL(NAN));
|
||||
|
||||
krk_pop();
|
||||
return OBJECT_VAL(module);
|
||||
}
|
||||
|
@ -23,6 +23,9 @@
|
||||
/* Did you know this is actually specified to not exist in a header? */
|
||||
extern char ** environ;
|
||||
|
||||
static KrkClass * os_Environ;
|
||||
static KrkClass * os_stat_result;
|
||||
|
||||
#define DO_KEY(key) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)krk_copyString(buf. key, strlen(buf .key)))
|
||||
#define S_KEY(key,val) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)val);
|
||||
|
||||
@ -89,7 +92,7 @@ KRK_Function(uname) {
|
||||
#endif
|
||||
|
||||
#define AS_Environ(o) (AS_INSTANCE(o))
|
||||
#define IS_Environ(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(Environ)))
|
||||
#define IS_Environ(o) (krk_isInstanceOf(o,os_Environ))
|
||||
#define CURRENT_CTYPE KrkInstance*
|
||||
|
||||
static int _setVar(KrkString * key, KrkString * val) {
|
||||
@ -141,7 +144,7 @@ KRK_Method(Environ,__delitem__) {
|
||||
|
||||
static void _loadEnviron(KrkInstance * module) {
|
||||
/* Create a new class to subclass `dict` */
|
||||
KrkClass * Environ = krk_makeClass(module, &KRK_BASE_CLASS(Environ), "_Environ", vm.baseClasses->dictClass);
|
||||
KrkClass * Environ = krk_makeClass(module, &os_Environ, "_Environ", vm.baseClasses->dictClass);
|
||||
krk_attachNamedObject(&module->fields, "_Environ", (KrkObj*)Environ);
|
||||
|
||||
/* Add our set method that should also call dict's set method */
|
||||
@ -553,7 +556,7 @@ KRK_Function(stat) {
|
||||
if (result == -1) {
|
||||
return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
|
||||
}
|
||||
KrkInstance * out = krk_newInstance(KRK_BASE_CLASS(stat_result));
|
||||
KrkInstance * out = krk_newInstance(os_stat_result);
|
||||
krk_push(OBJECT_VAL(out));
|
||||
|
||||
SET(st_dev);
|
||||
@ -571,7 +574,7 @@ KRK_Function(stat) {
|
||||
}
|
||||
#undef SET
|
||||
|
||||
#define IS_stat_result(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(stat_result)))
|
||||
#define IS_stat_result(o) (krk_isInstanceOf(o,os_stat_result))
|
||||
#define AS_stat_result(o) AS_INSTANCE(o)
|
||||
#define CURRENT_NAME self
|
||||
|
||||
@ -614,49 +617,7 @@ KRK_Method(stat_result,__repr__) {
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
KRK_Function(S_ISBLK) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISBLK(mode));
|
||||
}
|
||||
KRK_Function(S_ISCHR) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISCHR(mode));
|
||||
}
|
||||
KRK_Function(S_ISDIR) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISDIR(mode));
|
||||
}
|
||||
KRK_Function(S_ISFIFO) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISFIFO(mode));
|
||||
}
|
||||
KRK_Function(S_ISREG) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISREG(mode));
|
||||
}
|
||||
#ifndef _WIN32
|
||||
KRK_Function(S_ISLNK) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISLNK(mode));
|
||||
}
|
||||
KRK_Function(S_ISSOCK) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISSOCK(mode));
|
||||
}
|
||||
#endif
|
||||
|
||||
void krk_module_init_os(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_attachNamedObject(&vm.modules, "os", (KrkObj*)module);
|
||||
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("os"));
|
||||
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
|
||||
KRK_Module(os) {
|
||||
KRK_DOC(module, "@brief Provides access to low-level system operations.");
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -869,7 +830,7 @@ void krk_module_init_os(void) {
|
||||
_loadEnviron(module);
|
||||
|
||||
/* Nothing special */
|
||||
KrkClass * stat_result = krk_makeClass(module, &KRK_BASE_CLASS(stat_result), "stat_result", vm.baseClasses->objectClass);
|
||||
KrkClass * stat_result = krk_makeClass(module, &os_stat_result, "stat_result", vm.baseClasses->objectClass);
|
||||
BIND_METHOD(stat_result,__repr__);
|
||||
krk_finalizeClass(stat_result);
|
||||
|
||||
@ -877,23 +838,6 @@ void krk_module_init_os(void) {
|
||||
"@brief Get the status of a file\n"
|
||||
"@arguments path\n\n"
|
||||
"Runs the @c stat system call on @p path. Returns a @ref stat_result.\n");
|
||||
|
||||
module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_attachNamedObject(&vm.modules, "stat", (KrkObj*)module);
|
||||
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("stat"));
|
||||
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
|
||||
KRK_DOC(module,
|
||||
"@brief Functions to check results from @ref stat calls.");
|
||||
|
||||
BIND_FUNC(module,S_ISBLK);
|
||||
BIND_FUNC(module,S_ISCHR);
|
||||
BIND_FUNC(module,S_ISDIR);
|
||||
BIND_FUNC(module,S_ISFIFO);
|
||||
BIND_FUNC(module,S_ISREG);
|
||||
#ifndef _WIN32
|
||||
BIND_FUNC(module,S_ISLNK);
|
||||
BIND_FUNC(module,S_ISSOCK);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -58,16 +58,11 @@ KRK_Function(seed) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KrkValue krk_module_onload_random(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_push(OBJECT_VAL(module));
|
||||
|
||||
KRK_Module(random) {
|
||||
KRK_DOC(module, "Functions for generating pseudo-random numbers.");
|
||||
|
||||
BIND_FUNC(module, random);
|
||||
BIND_FUNC(module, seed);
|
||||
|
||||
FUNC_NAME(krk,seed)(0,NULL,0);
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
@ -14,6 +14,9 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef AF_UNIX
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include <kuroko/vm.h>
|
||||
@ -36,27 +39,18 @@ struct socket {
|
||||
#define CURRENT_CTYPE struct socket *
|
||||
#define CURRENT_NAME self
|
||||
|
||||
#define NAMED_ARG(name,type,ctype,def,ind) \
|
||||
ctype name = def; \
|
||||
if (argc > ind) { \
|
||||
CHECK_ARG(ind,type,ctype,_tmp); \
|
||||
name = _tmp; \
|
||||
} \
|
||||
if (hasKw) { \
|
||||
KrkValue tmp; \
|
||||
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S(#name)), &tmp)) { \
|
||||
if (!IS_ ## type (tmp)) return TYPE_ERROR(type,tmp); \
|
||||
name = AS_ ## type (tmp); \
|
||||
} \
|
||||
}
|
||||
|
||||
KRK_Method(socket,__init__) {
|
||||
METHOD_TAKES_AT_MOST(3);
|
||||
|
||||
/* Complex argument processing time... */
|
||||
NAMED_ARG(family,int,krk_integer_type,AF_INET,1);
|
||||
NAMED_ARG(type,int,krk_integer_type,SOCK_STREAM,2);
|
||||
NAMED_ARG(proto,int,krk_integer_type,0,3);
|
||||
int family = AF_INET;
|
||||
int type = SOCK_STREAM;
|
||||
int proto = 0;
|
||||
|
||||
if (!krk_parseArgs(".|iii:socket",
|
||||
(const char *[]){"family","type","proto"},
|
||||
&family, &type, &proto)) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
int result = socket(family,type,proto);
|
||||
|
||||
@ -69,7 +63,7 @@ KRK_Method(socket,__init__) {
|
||||
self->type = type;
|
||||
self->proto = proto;
|
||||
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
static char * _af_name(int afval) {
|
||||
@ -122,7 +116,7 @@ static int socket_parse_address(struct socket * self, KrkValue address, struct s
|
||||
return 1;
|
||||
}
|
||||
if (!IS_str(addr->values.values[0])) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Address should be int, not '%T'", addr->values.values[0]);
|
||||
krk_runtimeError(vm.exceptions->typeError, "Address should be str, not '%T'", addr->values.values[0]);
|
||||
return 1;
|
||||
}
|
||||
if (!IS_int(addr->values.values[1])) {
|
||||
@ -171,6 +165,87 @@ static int socket_parse_address(struct socket * self, KrkValue address, struct s
|
||||
|
||||
return 0;
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
} else if (self->family == AF_INET6) {
|
||||
/* Should be 2-tuple */
|
||||
if (!IS_tuple(address)) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Expected 2-tuple, not '%T'", address);
|
||||
return 1;
|
||||
}
|
||||
KrkTuple * addr = AS_TUPLE(address);
|
||||
if (addr->values.count != 2) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Expected 2-tuple, not '%T'", address);
|
||||
return 1;
|
||||
}
|
||||
if (!IS_str(addr->values.values[0])) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Address should be str, not '%T'", addr->values.values[0]);
|
||||
return 1;
|
||||
}
|
||||
if (!IS_int(addr->values.values[1])) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Port should be int, not '%T'", addr->values.values[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!AS_STRING(addr->values.values[0])->length) {
|
||||
struct sockaddr_in6 * sin = (struct sockaddr_in6*)sock_addr;
|
||||
*sock_size = sizeof(struct sockaddr_in6);
|
||||
sin->sin6_family = AF_INET6;
|
||||
sin->sin6_port = htons(AS_int(addr->values.values[1]));
|
||||
sin->sin6_addr = in6addr_any;
|
||||
return 0;
|
||||
} else {
|
||||
struct addrinfo *result;
|
||||
struct addrinfo *res;
|
||||
int error = getaddrinfo(AS_CSTRING(addr->values.values[0]), NULL, NULL, &result);
|
||||
if (error != 0) {
|
||||
krk_runtimeError(SocketError, "getaddrinfo() returned error: %d", error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int found = 0;
|
||||
res = result;
|
||||
while (res) {
|
||||
if (res->ai_family == AF_INET6) {
|
||||
found = 1;
|
||||
*sock_size = res->ai_addrlen;
|
||||
memcpy(sock_addr, res->ai_addr, *sock_size);
|
||||
break;
|
||||
}
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
|
||||
if (!found) {
|
||||
krk_runtimeError(SocketError, "no suitable address");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct sockaddr_in6 * sin = (struct sockaddr_in6*)sock_addr;
|
||||
sin->sin6_family = AF_INET6;
|
||||
sin->sin6_port = htons(AS_int(addr->values.values[1]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef AF_UNIX
|
||||
} else if (self->family == AF_UNIX) {
|
||||
if (!IS_str(address)) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Address should be str, not '%T'", address);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (AS_STRING(address)->length > 107) {
|
||||
krk_runtimeError(vm.exceptions->valueError, "Address is too long");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct sockaddr_un * sun = (struct sockaddr_un*)sock_addr;
|
||||
*sock_size = sizeof(struct sockaddr_un);
|
||||
sun->sun_family = AF_UNIX;
|
||||
memcpy(sun->sun_path, AS_CSTRING(address), AS_STRING(address)->length + 1);
|
||||
return 0;
|
||||
#endif
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->notImplementedError, "Not implemented.");
|
||||
return 1;
|
||||
@ -266,10 +341,11 @@ KRK_Method(socket,accept) {
|
||||
outTuple->values.count = 1;
|
||||
krk_pop();
|
||||
|
||||
KrkTuple * addrTuple = krk_newTuple(2); /* TODO: Other formats */
|
||||
krk_push(OBJECT_VAL(addrTuple));
|
||||
|
||||
if (self->family == AF_INET) {
|
||||
KrkTuple * addrTuple = krk_newTuple(2); /* TODO: Other formats */
|
||||
krk_push(OBJECT_VAL(addrTuple));
|
||||
|
||||
char hostname[NI_MAXHOST] = "";
|
||||
getnameinfo((struct sockaddr*)&addr, addrlen, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
||||
|
||||
@ -277,6 +353,24 @@ KRK_Method(socket,accept) {
|
||||
addrTuple->values.count = 1;
|
||||
addrTuple->values.values[1] = INTEGER_VAL(htons(((struct sockaddr_in*)&addr)->sin_port));
|
||||
addrTuple->values.count = 2;
|
||||
#ifdef AF_INET6
|
||||
} else if (self->family == AF_INET6) {
|
||||
KrkTuple * addrTuple = krk_newTuple(2); /* TODO: Other formats */
|
||||
krk_push(OBJECT_VAL(addrTuple));
|
||||
|
||||
char hostname[NI_MAXHOST] = "";
|
||||
getnameinfo((struct sockaddr*)&addr, addrlen, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
||||
|
||||
addrTuple->values.values[0] = OBJECT_VAL(krk_copyString(hostname,strlen(hostname)));
|
||||
addrTuple->values.count = 1;
|
||||
addrTuple->values.values[1] = INTEGER_VAL(htons(((struct sockaddr_in6*)&addr)->sin6_port));
|
||||
addrTuple->values.count = 2;
|
||||
#endif
|
||||
#ifdef AF_UNIX
|
||||
} else if (self->family == AF_UNIX) {
|
||||
/* ignore remote path because it's meaningless? */
|
||||
krk_push(OBJECT_VAL(S("")));
|
||||
#endif
|
||||
} else {
|
||||
krk_push(NONE_VAL());
|
||||
}
|
||||
@ -404,10 +498,22 @@ KRK_Function(htons) {
|
||||
return INTEGER_VAL(htons(value));
|
||||
}
|
||||
|
||||
KrkValue krk_module_onload_socket(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_push(OBJECT_VAL(module));
|
||||
KRK_Method(socket,family) {
|
||||
if (argc > 1) return krk_runtimeError(vm.exceptions->attributeError, "readonly attribute");
|
||||
return INTEGER_VAL(self->family);
|
||||
}
|
||||
|
||||
KRK_Method(socket,type) {
|
||||
if (argc > 1) return krk_runtimeError(vm.exceptions->attributeError, "readonly attribute");
|
||||
return INTEGER_VAL(self->type);
|
||||
}
|
||||
|
||||
KRK_Method(socket,proto) {
|
||||
if (argc > 1) return krk_runtimeError(vm.exceptions->attributeError, "readonly attribute");
|
||||
return INTEGER_VAL(self->proto);
|
||||
}
|
||||
|
||||
KRK_Module(socket) {
|
||||
KRK_DOC(module, "Lightweight wrapper around the standard Berkeley sockets interface.");
|
||||
|
||||
KrkClass * socket = krk_makeClass(module, &SocketClass, "socket", vm.baseClasses->objectClass);
|
||||
@ -459,7 +565,11 @@ KrkValue krk_module_onload_socket(void) {
|
||||
"@arguments level,optname,value\n\n"
|
||||
"@p level and @p optname should be integer values defined by @c SOL and @c SO options. "
|
||||
"@p value must be either an @ref int or a @ref bytes object.");
|
||||
krk_defineNative(&socket->methods,"__str__", FUNC_NAME(socket,__repr__));
|
||||
|
||||
BIND_PROP(socket,family);
|
||||
BIND_PROP(socket,type);
|
||||
BIND_PROP(socket,proto);
|
||||
|
||||
krk_finalizeClass(SocketClass);
|
||||
|
||||
BIND_FUNC(module, htons);
|
||||
@ -509,6 +619,4 @@ KrkValue krk_module_onload_socket(void) {
|
||||
krk_makeClass(module, &SocketError, "SocketError", vm.exceptions->baseException);
|
||||
KRK_DOC(SocketError, "Raised on faults from socket functions.");
|
||||
krk_finalizeClass(SocketError);
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
57
src/modules/module_stat.c
Normal file
57
src/modules/module_stat.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include <sys/stat.h>
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
KRK_Function(S_ISBLK) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISBLK(mode));
|
||||
}
|
||||
KRK_Function(S_ISCHR) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISCHR(mode));
|
||||
}
|
||||
KRK_Function(S_ISDIR) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISDIR(mode));
|
||||
}
|
||||
KRK_Function(S_ISFIFO) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISFIFO(mode));
|
||||
}
|
||||
KRK_Function(S_ISREG) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISREG(mode));
|
||||
}
|
||||
#ifndef _WIN32
|
||||
KRK_Function(S_ISLNK) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISLNK(mode));
|
||||
}
|
||||
KRK_Function(S_ISSOCK) {
|
||||
int mode;
|
||||
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
|
||||
return INTEGER_VAL(S_ISSOCK(mode));
|
||||
}
|
||||
#endif
|
||||
|
||||
KRK_Module(stat) {
|
||||
KRK_DOC(module, "@brief Functions to check results from @ref stat calls.");
|
||||
|
||||
BIND_FUNC(module,S_ISBLK);
|
||||
BIND_FUNC(module,S_ISCHR);
|
||||
BIND_FUNC(module,S_ISDIR);
|
||||
BIND_FUNC(module,S_ISFIFO);
|
||||
BIND_FUNC(module,S_ISREG);
|
||||
#ifndef _WIN32
|
||||
BIND_FUNC(module,S_ISLNK);
|
||||
BIND_FUNC(module,S_ISSOCK);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
276
src/modules/module_time.c
Normal file
276
src/modules/module_time.c
Normal file
@ -0,0 +1,276 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/value.h>
|
||||
#include <kuroko/object.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
KRK_Function(sleep) {
|
||||
FUNCTION_TAKES_EXACTLY(1);
|
||||
|
||||
if (!IS_INTEGER(argv[0]) && !IS_FLOATING(argv[0])) {
|
||||
return TYPE_ERROR(int or float,argv[0]);
|
||||
}
|
||||
|
||||
unsigned int usecs = (IS_INTEGER(argv[0]) ? AS_INTEGER(argv[0]) :
|
||||
(IS_FLOATING(argv[0]) ? AS_FLOATING(argv[0]) : 0)) *
|
||||
1000000;
|
||||
|
||||
usleep(usecs);
|
||||
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
|
||||
KRK_Function(time) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
|
||||
double out = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
|
||||
|
||||
return FLOATING_VAL(out);
|
||||
}
|
||||
|
||||
static KrkClass * struct_time;
|
||||
|
||||
struct struct_time_obj {
|
||||
KrkInstance inst;
|
||||
struct tm _value;
|
||||
};
|
||||
|
||||
#define IS_struct_time(o) (krk_isInstanceOf(o,struct_time))
|
||||
#define AS_struct_time(o) ((struct struct_time_obj*)AS_OBJECT(o))
|
||||
#define CURRENT_CTYPE struct struct_time_obj *
|
||||
#define CURRENT_NAME self
|
||||
|
||||
KRK_Method(struct_time,__init__) {
|
||||
KrkValue seq;
|
||||
if (!krk_parseArgs(".V:struct_time", (const char *[]){"iterable"}, &seq)) return NONE_VAL();
|
||||
if (!IS_TUPLE(seq) || AS_TUPLE(seq)->values.count != 9) return krk_runtimeError(vm.exceptions->notImplementedError, "sequence other than 9-tuple unsupported");
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
if (!IS_INTEGER(AS_TUPLE(seq)->values.values[i])) return krk_runtimeError(vm.exceptions->valueError, "expected int, not %T", AS_TUPLE(seq)->values.values[i]);
|
||||
}
|
||||
|
||||
self->_value.tm_year = AS_INTEGER(AS_TUPLE(seq)->values.values[0]) - 1900;
|
||||
self->_value.tm_mon = AS_INTEGER(AS_TUPLE(seq)->values.values[1]) - 1;
|
||||
self->_value.tm_mday = AS_INTEGER(AS_TUPLE(seq)->values.values[2]);
|
||||
self->_value.tm_hour = AS_INTEGER(AS_TUPLE(seq)->values.values[3]);
|
||||
self->_value.tm_min = AS_INTEGER(AS_TUPLE(seq)->values.values[4]);
|
||||
self->_value.tm_sec = AS_INTEGER(AS_TUPLE(seq)->values.values[5]);
|
||||
self->_value.tm_wday = (AS_INTEGER(AS_TUPLE(seq)->values.values[6])+6)%7;
|
||||
self->_value.tm_yday = AS_INTEGER(AS_TUPLE(seq)->values.values[7]) - 1;
|
||||
self->_value.tm_isdst = AS_INTEGER(AS_TUPLE(seq)->values.values[8]);
|
||||
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(struct_time,tm_year) { return INTEGER_VAL(self->_value.tm_year + 1900); } /* struct tm is 1900-indexed, snakes are not */
|
||||
KRK_Method(struct_time,tm_mon) { return INTEGER_VAL(self->_value.tm_mon + 1); } /* struct tm is 0-indexed, snakes are not */
|
||||
KRK_Method(struct_time,tm_mday) { return INTEGER_VAL(self->_value.tm_mday); }
|
||||
KRK_Method(struct_time,tm_hour) { return INTEGER_VAL(self->_value.tm_hour); }
|
||||
KRK_Method(struct_time,tm_min) { return INTEGER_VAL(self->_value.tm_min); }
|
||||
KRK_Method(struct_time,tm_sec) { return INTEGER_VAL(self->_value.tm_sec); }
|
||||
KRK_Method(struct_time,tm_wday) { return INTEGER_VAL((self->_value.tm_wday+1)%7); } /* struct tm has Sunday = 0, but snakes use Monday = 0 */
|
||||
KRK_Method(struct_time,tm_yday) { return INTEGER_VAL(self->_value.tm_yday+1); } /* struct tm is from 0, but snakes start from 1 */
|
||||
KRK_Method(struct_time,tm_isdst) { return INTEGER_VAL(self->_value.tm_isdst); }
|
||||
|
||||
KRK_Method(struct_time,__repr__) {
|
||||
return krk_stringFromFormat(
|
||||
"time.struct_time(tm_year=%d, tm_mon=%d, tm_mday=%d, tm_hour=%d, tm_min=%d, "
|
||||
"tm_sec=%d, tm_wday=%d, tm_yday=%d, tm_isdst=%d)",
|
||||
self->_value.tm_year + 1900,
|
||||
self->_value.tm_mon + 1,
|
||||
self->_value.tm_mday,
|
||||
self->_value.tm_hour,
|
||||
self->_value.tm_min,
|
||||
self->_value.tm_sec,
|
||||
(self->_value.tm_wday + 1) % 7,
|
||||
self->_value.tm_yday + 1,
|
||||
self->_value.tm_isdst);
|
||||
}
|
||||
|
||||
static time_t time_or_now(int has_arg, long long secs) {
|
||||
if (!has_arg) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
return (time_t)tv.tv_sec;
|
||||
} else {
|
||||
return (time_t)secs;
|
||||
}
|
||||
}
|
||||
|
||||
static void tm_or_now(const struct struct_time_obj * t, struct tm * _time) {
|
||||
if (t) {
|
||||
memcpy(_time,&t->_value,sizeof(struct tm));
|
||||
} else {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
time_t time = tv.tv_sec;
|
||||
localtime_r(&time,_time);
|
||||
}
|
||||
}
|
||||
|
||||
KRK_Function(localtime) {
|
||||
int gave_seconds;
|
||||
long long seconds;
|
||||
if (!krk_parseArgs("|L?",(const char*[]){"seconds"},&gave_seconds, &seconds)) return NONE_VAL();
|
||||
time_t time = time_or_now(gave_seconds, seconds);
|
||||
|
||||
/* Create a struct_time to store result in */
|
||||
CURRENT_CTYPE out = (CURRENT_CTYPE)krk_newInstance(struct_time);
|
||||
krk_push(OBJECT_VAL(out));
|
||||
|
||||
if (!localtime_r(&time, &out->_value)) return krk_runtimeError(vm.exceptions->valueError, "?");
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
static KrkValue krk_asctime(const struct tm *_time) {
|
||||
/* asctime is normally locale-aware, but the snake function is not, so we do this manually */
|
||||
static const char * monNames[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
|
||||
static const char * dayNames[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
|
||||
|
||||
char buf[40] = {0};
|
||||
|
||||
/* The normal strftime string for this is %a %b %d %T %Y
|
||||
* Day Mon DD HH:MM:SS YYYY */
|
||||
snprintf(buf,39, "%s %s%3d %.2d:%.2d:%.2d %d",
|
||||
dayNames[_time->tm_wday % 7],
|
||||
monNames[_time->tm_mon % 12],
|
||||
_time->tm_mday,
|
||||
_time->tm_hour,
|
||||
_time->tm_min,
|
||||
_time->tm_sec,
|
||||
_time->tm_year + 1900);
|
||||
|
||||
return OBJECT_VAL(krk_copyString(buf,strlen(buf)));
|
||||
}
|
||||
|
||||
KRK_Function(asctime) {
|
||||
struct struct_time_obj * t = NULL;
|
||||
if (!krk_parseArgs("|O!",(const char*[]){"t"},struct_time,&t)) return NONE_VAL();
|
||||
struct tm _time;
|
||||
tm_or_now(t,&_time);
|
||||
return krk_asctime(&_time);
|
||||
}
|
||||
|
||||
KRK_Function(ctime) {
|
||||
int has_arg;
|
||||
long long secs;
|
||||
if (!krk_parseArgs("|L?",(const char*[]){"secs"},&has_arg,&secs)) return NONE_VAL();
|
||||
time_t time = time_or_now(has_arg, secs);
|
||||
struct tm _time;
|
||||
if (!localtime_r(&time, &_time)) return krk_runtimeError(vm.exceptions->valueError, "?");
|
||||
|
||||
return krk_asctime(&_time);
|
||||
}
|
||||
|
||||
KRK_Function(gmtime) {
|
||||
int gave_seconds;
|
||||
long long seconds;
|
||||
if (!krk_parseArgs("|L?",(const char*[]){"secs"},&gave_seconds, &seconds)) return NONE_VAL();
|
||||
time_t time = time_or_now(gave_seconds, seconds);
|
||||
|
||||
/* Create a struct_time to store result in */
|
||||
CURRENT_CTYPE out = (CURRENT_CTYPE)krk_newInstance(struct_time);
|
||||
krk_push(OBJECT_VAL(out));
|
||||
|
||||
if (!gmtime_r(&time, &out->_value)) return krk_runtimeError(vm.exceptions->valueError, "?");
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
KRK_Function(mktime) {
|
||||
struct struct_time_obj * t;
|
||||
if (!krk_parseArgs("O!",(const char*[]){"t"},struct_time,&t)) return NONE_VAL();
|
||||
|
||||
struct tm _time;
|
||||
memcpy(&_time,&t->_value,sizeof(struct tm));
|
||||
_time.tm_wday = -1;
|
||||
time_t out = mktime(&_time);
|
||||
if (out == -1 && _time.tm_wday == -1) return krk_runtimeError(vm.exceptions->valueError, "invalid argument to mktime");
|
||||
return FLOATING_VAL(out);
|
||||
}
|
||||
|
||||
KRK_Function(strftime) {
|
||||
const char * format;
|
||||
struct struct_time_obj * t = NULL;
|
||||
if (!krk_parseArgs("s|O!",(const char*[]){"format","t"},&format,struct_time,&t)) return NONE_VAL();
|
||||
struct tm _time;
|
||||
tm_or_now(t,&_time);
|
||||
|
||||
/* strftime wants a buffer size, but we have no way of knowing. Following
|
||||
* what CPython does, start from 1024 and try doubling until we reach
|
||||
* the length of our format string * 256, and then give up. */
|
||||
size_t fmt_len = strlen(format);
|
||||
size_t size = 1024;
|
||||
while (1) {
|
||||
char * buf = malloc(size);
|
||||
size_t ret = strftime(buf,size,format,&_time);
|
||||
if (ret || size > fmt_len * 256) {
|
||||
krk_push(OBJECT_VAL(krk_copyString(buf,ret)));
|
||||
free(buf);
|
||||
return krk_pop();
|
||||
}
|
||||
size *= 2;
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
KRK_Module(time) {
|
||||
KRK_DOC(module, "@brief Provides timekeeping functions.");
|
||||
KRK_DOC(BIND_FUNC(module,sleep), "@brief Pause execution of the current thread.\n"
|
||||
"@arguments secs\n\n"
|
||||
"Uses the system @c usleep() function to sleep for @p secs seconds, which may be a @ref float or @ref int. "
|
||||
"The available precision is platform-dependent.");
|
||||
KRK_DOC(BIND_FUNC(module,time), "@brief Return the elapsed seconds since the system epoch.\n\n"
|
||||
"Returns a @ref float representation of the number of seconds since the platform's epoch date. "
|
||||
"On POSIX platforms, this is the number of seconds since 1 January 1970. "
|
||||
"The precision of the return value is platform-dependent.");
|
||||
|
||||
krk_makeClass(module, &struct_time, "struct_time", KRK_BASE_CLASS(object));
|
||||
struct_time->allocSize = sizeof(struct struct_time_obj);
|
||||
KRK_DOC(struct_time, "Time value returned by various functions.");
|
||||
KRK_DOC(BIND_METHOD(struct_time,__init__), "@arguments iterable: tuple\n\n"
|
||||
"Create a @ref struct_time from a 9-tuple of @ref int values.\n"
|
||||
"The format of @p iterable is `(tm_year,tm_mon,tm_mday,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)`.");
|
||||
KRK_DOC(BIND_PROP(struct_time,tm_year), "Calendar year");
|
||||
KRK_DOC(BIND_PROP(struct_time,tm_mon), "Month, [1, 12]");
|
||||
KRK_DOC(BIND_PROP(struct_time,tm_mday), "Day of the month, [1, 31]");
|
||||
KRK_DOC(BIND_PROP(struct_time,tm_hour), "Clock hour, [0, 23]");
|
||||
KRK_DOC(BIND_PROP(struct_time,tm_min), "Clock minute, [0, 59]");
|
||||
KRK_DOC(BIND_PROP(struct_time,tm_sec), "Clock seconds, [0, 61] (maybe, due to leap seconds, depends on platform)");
|
||||
KRK_DOC(BIND_PROP(struct_time,tm_wday), "Day of week, [0, 6], 0 is Monday.");
|
||||
KRK_DOC(BIND_PROP(struct_time,tm_yday), "Day of year [1, 366]");
|
||||
KRK_DOC(BIND_PROP(struct_time,tm_isdst), "0, 1, -1 for unknown");
|
||||
BIND_METHOD(struct_time,__repr__);
|
||||
krk_finalizeClass(struct_time);
|
||||
|
||||
KRK_DOC(BIND_FUNC(module,localtime), "@brief Convert seconds since epoch to local time.\n"
|
||||
"@arguments seconds=time.time()\n\n"
|
||||
"If @p seconds is not provided, the current @ref time is used.");
|
||||
KRK_DOC(BIND_FUNC(module,asctime), "@brief Convert time to string.\n"
|
||||
"@arguments t=time.localtime()\n\n"
|
||||
"If @p t is not provided, the current @ref localtime is used.");
|
||||
KRK_DOC(BIND_FUNC(module,ctime), "@brief Convert seconds since epoch to string.\n"
|
||||
"@arguments secs=time.time()\n\n"
|
||||
"If @p secs is not provided, the current @ref time is used.");
|
||||
KRK_DOC(BIND_FUNC(module,gmtime), "@brief Convert seconds since epoch to UTC time.\n"
|
||||
"@arguments secs=time.time()\n\n"
|
||||
"If @p secs is not provided, the current @ref time is used.");
|
||||
KRK_DOC(BIND_FUNC(module,mktime), "@brief Convert from local time to seconds since epoch.\n"
|
||||
"@arguments t\n\n"
|
||||
"For compatibility with @ref time a @ref float is returned.");
|
||||
KRK_DOC(BIND_FUNC(module,strftime), "@brief Format time string with system function.\n"
|
||||
"@arguments format,t=time.localtime()\n\n"
|
||||
"Uses the system `strftime` C function to convert a @ref struct_time to a string.\n"
|
||||
"If @p t is not provided, the current @ref localtime is used.");
|
||||
}
|
||||
|
@ -35,14 +35,8 @@ KRK_Function(timeit) {
|
||||
return FLOATING_VAL(after-before);
|
||||
}
|
||||
|
||||
KrkValue krk_module_onload_timeit(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_push(OBJECT_VAL(module));
|
||||
|
||||
KRK_Module(timeit) {
|
||||
KRK_DOC(module, "@brief Run functions very quickly without loop overhead from the interpreter.");
|
||||
|
||||
BIND_FUNC(module,timeit);
|
||||
|
||||
krk_pop();
|
||||
return OBJECT_VAL(module);
|
||||
}
|
||||
|
@ -17,16 +17,12 @@ KRK_Function(wcwidth) {
|
||||
return INTEGER_VAL(wcwidth(codepoint));
|
||||
}
|
||||
|
||||
KrkValue krk_module_onload_wcwidth(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_push(OBJECT_VAL(module));
|
||||
KRK_Module(wcwidth) {
|
||||
KRK_DOC(module, "Character widths.");
|
||||
BIND_FUNC(module, wcwidth);
|
||||
|
||||
#ifndef _WIN32
|
||||
setlocale(LC_ALL, "");
|
||||
#endif
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
|
196
src/obj_base.c
196
src/obj_base.c
@ -6,22 +6,114 @@
|
||||
|
||||
#define CURRENT_NAME self
|
||||
|
||||
#define IS_type(o) (1)
|
||||
#define AS_type(o) (o)
|
||||
#define CURRENT_CTYPE KrkValue
|
||||
KRK_Method(type,__init__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
return OBJECT_VAL(krk_getType(argv[1]));
|
||||
}
|
||||
#undef IS_type
|
||||
#undef AS_type
|
||||
#undef CURRENT_CTYPE
|
||||
|
||||
#define IS_type(o) (IS_CLASS(o))
|
||||
#define AS_type(o) (AS_CLASS(o))
|
||||
|
||||
#define CURRENT_CTYPE KrkClass *
|
||||
|
||||
static void _callSetName(KrkClass * _class) {
|
||||
KrkValue setnames = krk_list_of(0,NULL,0);
|
||||
krk_push(setnames);
|
||||
extern FUNC_SIG(list,append);
|
||||
|
||||
/* The semantics of this require that we first collect all of the relevant items... */
|
||||
for (size_t i = 0; i < _class->methods.capacity; ++i) {
|
||||
KrkTableEntry * entry = &_class->methods.entries[i];
|
||||
if (!IS_KWARGS(entry->key)) {
|
||||
KrkClass * type = krk_getType(entry->value);
|
||||
if (type->_set_name) {
|
||||
FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->key},0);
|
||||
FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->value},0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Then call __set_name__ on them */
|
||||
for (size_t i = 0; i < AS_LIST(setnames)->count; i += 2) {
|
||||
KrkValue name = AS_LIST(setnames)->values[i];
|
||||
KrkValue value = AS_LIST(setnames)->values[i+1];
|
||||
KrkClass * type = krk_getType(value);
|
||||
if (type->_set_name) {
|
||||
krk_push(value);
|
||||
krk_push(OBJECT_VAL(_class));
|
||||
krk_push(name);
|
||||
krk_callDirect(type->_set_name, 3);
|
||||
|
||||
/* If any of these raises an exception, bail; CPython raises
|
||||
* an outer exception, setting the cause, but I'm being lazy
|
||||
* at the moment... */
|
||||
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* List used to store name+value pairs */
|
||||
krk_pop();
|
||||
}
|
||||
|
||||
KRK_StaticMethod(type,__new__) {
|
||||
KrkClass * metaclass;
|
||||
KrkString * name;
|
||||
KrkClass * base;
|
||||
KrkDict * nspace;
|
||||
|
||||
if (!krk_parseArgs("O!O!O!O!~:type",
|
||||
(const char*[]){"cls","name","base","namespace"},
|
||||
vm.baseClasses->typeClass, &metaclass,
|
||||
vm.baseClasses->strClass, &name,
|
||||
vm.baseClasses->typeClass, &base,
|
||||
vm.baseClasses->dictClass, &nspace)) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (base->obj.flags & KRK_OBJ_FLAGS_NO_INHERIT) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "'%S' can not be subclassed", base->name);
|
||||
}
|
||||
|
||||
/* Now make a class */
|
||||
KrkClass * _class = krk_newClass(name, base);
|
||||
krk_push(OBJECT_VAL(_class));
|
||||
_class->_class = metaclass;
|
||||
|
||||
/* Now copy the values over */
|
||||
krk_tableAddAll(&nspace->entries, &_class->methods);
|
||||
|
||||
KrkValue tmp;
|
||||
|
||||
if (krk_tableGet_fast(&_class->methods, S("__class_getitem__"), &tmp) && IS_CLOSURE(tmp)) {
|
||||
AS_CLOSURE(tmp)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
|
||||
}
|
||||
|
||||
if (krk_tableGet_fast(&_class->methods, S("__init_subclass__"), &tmp) && IS_CLOSURE(tmp)) {
|
||||
AS_CLOSURE(tmp)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
|
||||
}
|
||||
|
||||
if (krk_tableGet_fast(&_class->methods, S("__new__"), &tmp) && IS_CLOSURE(tmp)) {
|
||||
AS_CLOSURE(tmp)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
|
||||
}
|
||||
|
||||
krk_finalizeClass(_class);
|
||||
_callSetName(_class);
|
||||
|
||||
/* Call super().__init_subclass__ */
|
||||
krk_push(NONE_VAL());
|
||||
if (!krk_bindMethodSuper(base,S("__init_subclass__"),_class)) {
|
||||
krk_pop(); /* none */
|
||||
} else {
|
||||
if (hasKw) {
|
||||
krk_push(KWARGS_VAL(KWARGS_DICT));
|
||||
krk_push(argv[argc]);
|
||||
krk_push(KWARGS_VAL(1));
|
||||
krk_callStack(3);
|
||||
} else {
|
||||
krk_callStack(0);
|
||||
}
|
||||
}
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
KRK_Method(type,__base__) {
|
||||
if (argc > 1) return krk_runtimeError(vm.exceptions->typeError, "__base__ can not be reassigned");
|
||||
return self->base ? OBJECT_VAL(self->base) : NONE_VAL();
|
||||
@ -43,15 +135,7 @@ KRK_Method(type,__file__) {
|
||||
return self->filename ? OBJECT_VAL(self->filename) : NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(type,__doc__) {
|
||||
if (argc > 1) {
|
||||
if (!IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]);
|
||||
self->docstring = AS_STRING(argv[1]);
|
||||
}
|
||||
return self->docstring ? OBJECT_VAL(self->docstring) : NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(type,__str__) {
|
||||
KRK_Method(type,__repr__) {
|
||||
/* Determine if this class has a module */
|
||||
KrkValue module = NONE_VAL();
|
||||
krk_tableGet(&self->methods, OBJECT_VAL(S("__module__")), &module);
|
||||
@ -90,21 +174,83 @@ KRK_Method(type,__getitem__) {
|
||||
return krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not subscriptable", "type");
|
||||
}
|
||||
|
||||
KRK_Method(type,__call__) {
|
||||
if (self == vm.baseClasses->typeClass) {
|
||||
if (argc == 2) {
|
||||
return OBJECT_VAL(krk_getType(argv[1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (!self->_new) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "%S() can not be built", self->name);
|
||||
}
|
||||
|
||||
KrkValue result;
|
||||
if (self->_new->type == KRK_OBJ_NATIVE) {
|
||||
/* Fast call to native __new__ function. */
|
||||
result = ((KrkNative*)self->_new)->function(argc,argv,hasKw);
|
||||
} else {
|
||||
/* Slow call: Put arguments back on the stack with kwargs call format */
|
||||
int argCount = argc;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
krk_push(argv[i]);
|
||||
}
|
||||
|
||||
if (hasKw) {
|
||||
argCount += 3;
|
||||
krk_push(KWARGS_VAL(KWARGS_DICT));
|
||||
krk_push(argv[argc]);
|
||||
krk_push(KWARGS_VAL(1));
|
||||
}
|
||||
|
||||
result = krk_callDirect(self->_new, argCount);
|
||||
}
|
||||
|
||||
/* If an exception happened in __new__, don't try to call __init__ even if the conditions would be right. */
|
||||
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return NONE_VAL();
|
||||
|
||||
if (self->_init != KRK_BASE_CLASS(object)->_init && self->_init != NULL && krk_isInstanceOf(result, self)) {
|
||||
/* Because we have to swap the class for the instance here, we can't do a fast call even
|
||||
* if __init__ is a native function, so we're stuck with the slow approach... */
|
||||
krk_push(result); /* once for safe keeping */
|
||||
krk_push(result); /* once as an argument */
|
||||
int argCount = argc;
|
||||
for (int i = 0; i < argc - 1; ++i) {
|
||||
krk_push(argv[i+1]);
|
||||
}
|
||||
|
||||
if (hasKw) {
|
||||
argCount += 3;
|
||||
krk_push(KWARGS_VAL(KWARGS_DICT));
|
||||
krk_push(argv[argc]);
|
||||
krk_push(KWARGS_VAL(1));
|
||||
}
|
||||
|
||||
KrkValue result = krk_callDirect(self->_init, argCount);
|
||||
if (!IS_NONE(result)) {
|
||||
fprintf(stderr, "Warning: Non-None result returned from %s.__init__\n",
|
||||
self->name->chars);
|
||||
}
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
_noexport
|
||||
void _createAndBind_type(void) {
|
||||
KrkClass * type = ADD_BASE_CLASS(vm.baseClasses->typeClass, "type", vm.baseClasses->objectClass);
|
||||
type->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
type->allocSize = sizeof(KrkClass);
|
||||
|
||||
BIND_PROP(type,__base__);
|
||||
BIND_PROP(type,__file__);
|
||||
BIND_PROP(type,__doc__);
|
||||
BIND_PROP(type,__name__);
|
||||
|
||||
BIND_METHOD(type,__init__);
|
||||
BIND_METHOD(type,__str__);
|
||||
BIND_METHOD(type,__repr__);
|
||||
BIND_METHOD(type,__subclasses__);
|
||||
BIND_METHOD(type,__getitem__);
|
||||
krk_defineNative(&type->methods,"__repr__",FUNC_NAME(type,__str__));
|
||||
BIND_METHOD(type,__call__);
|
||||
BIND_STATICMETHOD(type,__new__);
|
||||
|
||||
krk_finalizeClass(type);
|
||||
KRK_DOC(type, "Obtain the object representation of the class of an object.");
|
||||
|
@ -34,7 +34,7 @@ static int _bytes_callback(void * context, const KrkValue * values, size_t count
|
||||
return 0;
|
||||
}
|
||||
|
||||
KRK_Method(bytes,__init__) {
|
||||
KRK_StaticMethod(bytes,__new__) {
|
||||
if (argc < 2) return OBJECT_VAL(krk_newBytes(0,NULL));
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
|
||||
@ -275,7 +275,7 @@ KRK_Method(bytesiterator,__init__) {
|
||||
CHECK_ARG(1,bytes,KrkBytes*,bytes);
|
||||
self->l = argv[1];
|
||||
self->i = 0;
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(bytesiterator,__call__) {
|
||||
@ -304,10 +304,11 @@ KRK_Method(bytearray,__init__) {
|
||||
self->actual = OBJECT_VAL(krk_newBytes(AS_BYTES(argv[1])->length, AS_BYTES(argv[1])->bytes));
|
||||
} else if (IS_INTEGER(argv[1])) {
|
||||
self->actual = OBJECT_VAL(krk_newBytes(AS_INTEGER(argv[1]),NULL));
|
||||
memset(AS_BYTES(self->actual)->bytes, 0, AS_BYTES(self->actual)->length);
|
||||
} else {
|
||||
return krk_runtimeError(vm.exceptions->valueError, "expected bytes");
|
||||
}
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
#undef IS_bytearray
|
||||
@ -324,15 +325,10 @@ KRK_Method(bytearray,__repr__) {
|
||||
METHOD_TAKES_NONE();
|
||||
struct StringBuilder sb = {0};
|
||||
pushStringBuilderStr(&sb, "bytearray(", 10);
|
||||
|
||||
krk_push(self->actual);
|
||||
KrkValue repred_bytes = krk_callDirect(vm.baseClasses->bytesClass->_reprer, 1);
|
||||
if (!IS_STRING(repred_bytes)) {
|
||||
/* Invalid repr of bytes? */
|
||||
discardStringBuilder(&sb);
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", self->actual)) {
|
||||
krk_discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
pushStringBuilderStr(&sb, AS_STRING(repred_bytes)->chars, AS_STRING(repred_bytes)->length);
|
||||
pushStringBuilder(&sb,')');
|
||||
return finishStringBuilder(&sb);
|
||||
}
|
||||
@ -420,7 +416,8 @@ _noexport
|
||||
void _createAndBind_bytesClass(void) {
|
||||
KrkClass * bytes = ADD_BASE_CLASS(vm.baseClasses->bytesClass, "bytes", vm.baseClasses->objectClass);
|
||||
bytes->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
KRK_DOC(BIND_METHOD(bytes,__init__),
|
||||
bytes->allocSize = 0;
|
||||
KRK_DOC(BIND_STATICMETHOD(bytes,__new__),
|
||||
"@brief An array of bytes.\n"
|
||||
"@arguments iter=None\n\n"
|
||||
"Creates a new @ref bytes object. If @p iter is provided, it should be a @ref tuple or @ref list "
|
||||
@ -435,7 +432,6 @@ void _createAndBind_bytesClass(void) {
|
||||
BIND_METHOD(bytes,__hash__);
|
||||
BIND_METHOD(bytes,decode);
|
||||
BIND_METHOD(bytes,join);
|
||||
krk_defineNative(&bytes->methods,"__str__",FUNC_NAME(bytes,__repr__)); /* alias */
|
||||
krk_finalizeClass(bytes);
|
||||
|
||||
KrkClass * bytesiterator = ADD_BASE_CLASS(vm.baseClasses->bytesiteratorClass, "bytesiterator", vm.baseClasses->objectClass);
|
||||
@ -460,6 +456,5 @@ void _createAndBind_bytesClass(void) {
|
||||
BIND_METHOD(bytearray,__eq__);
|
||||
BIND_METHOD(bytearray,__iter__);
|
||||
BIND_METHOD(bytearray,decode);
|
||||
krk_defineNative(&bytearray->methods,"__str__",FUNC_NAME(bytearray,__repr__)); /* alias */
|
||||
krk_finalizeClass(bytearray);
|
||||
}
|
||||
|
146
src/obj_dict.c
146
src/obj_dict.c
@ -4,6 +4,14 @@
|
||||
#include <kuroko/memory.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
#if defined(__TINYC__) || (defined(_MSC_VER) && !defined(__clang__))
|
||||
static int __builtin_clz(unsigned int x) {
|
||||
int i = 31;
|
||||
while (!(x & (1 << i)) && i >= 0) i--;
|
||||
return 31-i;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Exposed method called to produce dictionaries from `{expr: expr, ...}` sequences in managed code.
|
||||
* Expects arguments as `key,value,key,value`...
|
||||
@ -13,9 +21,15 @@ KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw) {
|
||||
KrkInstance * outDict = krk_newInstance(vm.baseClasses->dictClass);
|
||||
krk_push(OBJECT_VAL(outDict));
|
||||
krk_initTable(&((KrkDict*)outDict)->entries);
|
||||
krk_tableAdjustCapacity(&((KrkDict*)outDict)->entries, argc);
|
||||
for (int ind = 0; ind < argc; ind += 2) {
|
||||
krk_tableSet(&((KrkDict*)outDict)->entries, argv[ind], argv[ind+1]);
|
||||
if (argc) {
|
||||
size_t capacity = argc;
|
||||
size_t powerOfTwoCapacity = __builtin_clz(1) - __builtin_clz(capacity);
|
||||
if ((1UL << powerOfTwoCapacity) != capacity) powerOfTwoCapacity++;
|
||||
capacity = (1UL << powerOfTwoCapacity);
|
||||
krk_tableAdjustCapacity(&((KrkDict*)outDict)->entries, capacity);
|
||||
for (int ind = 0; ind < argc; ind += 2) {
|
||||
krk_tableSet(&((KrkDict*)outDict)->entries, argv[ind], argv[ind+1]);
|
||||
}
|
||||
}
|
||||
return krk_pop();
|
||||
}
|
||||
@ -87,7 +101,8 @@ KRK_Method(dict,__init__) {
|
||||
if (hasKw) {
|
||||
krk_tableAddAll(AS_DICT(argv[argc]), &self->entries);
|
||||
}
|
||||
return argv[0];
|
||||
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(dict,__eq__) {
|
||||
@ -152,8 +167,8 @@ KRK_Method(dict,__len__) {
|
||||
|
||||
KRK_Method(dict,__contains__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
KrkValue _unused;
|
||||
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &_unused));
|
||||
KrkValue v;
|
||||
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &v));
|
||||
}
|
||||
|
||||
KRK_Method(dict,capacity) {
|
||||
@ -173,35 +188,21 @@ KRK_Method(dict,__repr__) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
KrkTableEntry * entry = &self->entries.entries[i];
|
||||
if (IS_KWARGS(entry->key)) continue;
|
||||
if (c > 0) {
|
||||
pushStringBuilderStr(&sb, ", ", 2);
|
||||
}
|
||||
if (c) pushStringBuilderStr(&sb, ", ", 2);
|
||||
c++;
|
||||
|
||||
{
|
||||
KrkClass * type = krk_getType(entry->key);
|
||||
krk_push(entry->key);
|
||||
KrkValue result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) {
|
||||
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
|
||||
pushStringBuilderStr(&sb, ": ", 2);
|
||||
|
||||
{
|
||||
KrkClass * type = krk_getType(entry->value);
|
||||
krk_push(entry->value);
|
||||
KrkValue result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) {
|
||||
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
|
||||
}
|
||||
}
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->value)) goto _error;
|
||||
}
|
||||
|
||||
pushStringBuilder(&sb,'}');
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return finishStringBuilder(&sb);
|
||||
|
||||
_error:
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
krk_discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(dict,copy) {
|
||||
@ -316,7 +317,7 @@ KRK_Method(dictitems,__init__) {
|
||||
CHECK_ARG(1,dict,KrkDict*,source);
|
||||
self->dict = argv[1];
|
||||
self->i = 0;
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(dictitems,__iter__) {
|
||||
@ -327,7 +328,7 @@ KRK_Method(dictitems,__iter__) {
|
||||
|
||||
KRK_Method(dictitems,__call__) {
|
||||
do {
|
||||
if (self->i >= AS_DICT(self->dict)->capacity) return argv[0];
|
||||
if (self->i >= AS_DICT(self->dict)->used) return argv[0];
|
||||
if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
|
||||
KrkTuple * outValue = krk_newTuple(2);
|
||||
krk_push(OBJECT_VAL(outValue));
|
||||
@ -349,43 +350,27 @@ KRK_Method(dictitems,__repr__) {
|
||||
pushStringBuilderStr(&sb,"dictitems([",11);
|
||||
|
||||
size_t c = 0;
|
||||
size_t len = AS_DICT(self->dict)->capacity;
|
||||
size_t len = AS_DICT(self->dict)->used;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
KrkTableEntry * entry = &AS_DICT(self->dict)->entries[i];
|
||||
if (IS_KWARGS(entry->key)) continue;
|
||||
if (c > 0) {
|
||||
pushStringBuilderStr(&sb, ", ", 2);
|
||||
}
|
||||
if (c) pushStringBuilderStr(&sb, ", ", 2);
|
||||
c++;
|
||||
|
||||
pushStringBuilder(&sb,'(');
|
||||
|
||||
{
|
||||
KrkClass * type = krk_getType(entry->key);
|
||||
krk_push(entry->key);
|
||||
KrkValue result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) {
|
||||
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
|
||||
pushStringBuilderStr(&sb, ", ", 2);
|
||||
|
||||
{
|
||||
KrkClass * type = krk_getType(entry->value);
|
||||
krk_push(entry->value);
|
||||
KrkValue result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) {
|
||||
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->value)) goto _error;
|
||||
pushStringBuilder(&sb,')');
|
||||
}
|
||||
|
||||
pushStringBuilderStr(&sb,"])",2);
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return finishStringBuilder(&sb);
|
||||
|
||||
_error:
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
krk_discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
@ -400,7 +385,7 @@ KRK_Method(dictkeys,__init__) {
|
||||
CHECK_ARG(1,dict,KrkDict*,source);
|
||||
self->dict = argv[1];
|
||||
self->i = 0;
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(dictkeys,__iter__) {
|
||||
@ -412,7 +397,7 @@ KRK_Method(dictkeys,__iter__) {
|
||||
KRK_Method(dictkeys,__call__) {
|
||||
METHOD_TAKES_NONE();
|
||||
do {
|
||||
if (self->i >= AS_DICT(self->dict)->capacity) return argv[0];
|
||||
if (self->i >= AS_DICT(self->dict)->used) return argv[0];
|
||||
if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
|
||||
krk_push(AS_DICT(self->dict)->entries[self->i].key);
|
||||
self->i++;
|
||||
@ -430,28 +415,23 @@ KRK_Method(dictkeys,__repr__) {
|
||||
pushStringBuilderStr(&sb,"dictkeys([",10);
|
||||
|
||||
size_t c = 0;
|
||||
size_t len = AS_DICT(self->dict)->capacity;
|
||||
size_t len = AS_DICT(self->dict)->used;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
KrkTableEntry * entry = &AS_DICT(self->dict)->entries[i];
|
||||
if (IS_KWARGS(entry->key)) continue;
|
||||
if (c > 0) {
|
||||
pushStringBuilderStr(&sb, ", ", 2);
|
||||
}
|
||||
if (c) pushStringBuilderStr(&sb, ", ", 2);
|
||||
c++;
|
||||
|
||||
{
|
||||
KrkClass * type = krk_getType(entry->key);
|
||||
krk_push(entry->key);
|
||||
KrkValue result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) {
|
||||
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
|
||||
}
|
||||
}
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
|
||||
}
|
||||
|
||||
pushStringBuilderStr(&sb,"])",2);
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return finishStringBuilder(&sb);
|
||||
|
||||
_error:
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
krk_discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
@ -466,7 +446,7 @@ KRK_Method(dictvalues,__init__) {
|
||||
CHECK_ARG(1,dict,KrkDict*,source);
|
||||
self->dict = argv[1];
|
||||
self->i = 0;
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(dictvalues,__iter__) {
|
||||
@ -478,7 +458,7 @@ KRK_Method(dictvalues,__iter__) {
|
||||
KRK_Method(dictvalues,__call__) {
|
||||
METHOD_TAKES_NONE();
|
||||
do {
|
||||
if (self->i >= AS_DICT(self->dict)->capacity) return argv[0];
|
||||
if (self->i >= AS_DICT(self->dict)->used) return argv[0];
|
||||
if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
|
||||
krk_push(AS_DICT(self->dict)->entries[self->i].value);
|
||||
self->i++;
|
||||
@ -496,28 +476,23 @@ KRK_Method(dictvalues,__repr__) {
|
||||
pushStringBuilderStr(&sb,"dictvalues([",12);
|
||||
|
||||
size_t c = 0;
|
||||
size_t len = AS_DICT(self->dict)->capacity;
|
||||
size_t len = AS_DICT(self->dict)->used;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
KrkTableEntry * entry = &AS_DICT(self->dict)->entries[i];
|
||||
if (IS_KWARGS(entry->key)) continue;
|
||||
if (c > 0) {
|
||||
pushStringBuilderStr(&sb, ", ", 2);
|
||||
}
|
||||
if (c) pushStringBuilderStr(&sb, ", ", 2);
|
||||
c++;
|
||||
|
||||
{
|
||||
KrkClass * type = krk_getType(entry->value);
|
||||
krk_push(entry->value);
|
||||
KrkValue result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) {
|
||||
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
|
||||
}
|
||||
}
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->value)) goto _error;
|
||||
}
|
||||
|
||||
pushStringBuilderStr(&sb,"])",2);
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return finishStringBuilder(&sb);
|
||||
|
||||
_error:
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
krk_discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
_noexport
|
||||
@ -546,7 +521,6 @@ void _createAndBind_dictClass(void) {
|
||||
BIND_METHOD(dict,setdefault);
|
||||
BIND_METHOD(dict,update);
|
||||
krk_defineNative(&dict->methods, "__iter__", FUNC_NAME(dict,keys));
|
||||
krk_defineNative(&dict->methods, "__str__", FUNC_NAME(dict,__repr__));
|
||||
krk_defineNative(&dict->methods, "__class_getitem__", krk_GenericAlias)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
|
||||
krk_attachNamedValue(&dict->methods, "__hash__", NONE_VAL());
|
||||
krk_finalizeClass(dict);
|
||||
|
@ -46,8 +46,7 @@ static KrkTuple * functionArgs(KrkCodeObject * _self) {
|
||||
#define CURRENT_NAME self
|
||||
#define CURRENT_CTYPE KrkValue
|
||||
|
||||
FUNC_SIG(function,__init__) {
|
||||
static __attribute__ ((unused)) const char* _method_name = "__init__";
|
||||
KRK_StaticMethod(function,__new__) {
|
||||
METHOD_TAKES_EXACTLY(3);
|
||||
CHECK_ARG(1,codeobject,KrkCodeObject*,code);
|
||||
|
||||
@ -138,7 +137,7 @@ KRK_Method(function,_ip_to_line) {
|
||||
return INTEGER_VAL(line);
|
||||
}
|
||||
|
||||
KRK_Method(function,__str__) {
|
||||
KRK_Method(function,__repr__) {
|
||||
METHOD_TAKES_NONE();
|
||||
|
||||
/* Do we have a qualified name? */
|
||||
@ -188,10 +187,26 @@ KRK_Method(function,__code__) {
|
||||
return OBJECT_VAL(AS_CLOSURE(self)->function);
|
||||
}
|
||||
|
||||
KRK_Method(function,__closure__) {
|
||||
ATTRIBUTE_NOT_ASSIGNABLE();
|
||||
if (!IS_CLOSURE(self)) {
|
||||
return OBJECT_VAL(krk_newTuple(0));
|
||||
}
|
||||
|
||||
size_t cnt = AS_CLOSURE(self)->upvalueCount;
|
||||
KrkTuple * out = krk_newTuple(cnt);
|
||||
krk_push(OBJECT_VAL(out));
|
||||
for (size_t i = 0; i < cnt; ++i) {
|
||||
out->values.values[out->values.count++] = OBJECT_VAL(AS_CLOSURE(self)->upvalues[i]);
|
||||
}
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
#define CURRENT_CTYPE KrkCodeObject*
|
||||
|
||||
FUNC_SIG(codeobject,__init__) {
|
||||
KRK_StaticMethod(codeobject,__new__) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "codeobject object is not instantiable");
|
||||
}
|
||||
|
||||
@ -200,7 +215,7 @@ KRK_Method(codeobject,__name__) {
|
||||
return self->name ? OBJECT_VAL(self->name) : OBJECT_VAL(S(""));
|
||||
}
|
||||
|
||||
KRK_Method(codeobject,__str__) {
|
||||
KRK_Method(codeobject,__repr__) {
|
||||
METHOD_TAKES_NONE();
|
||||
KrkValue s = FUNC_NAME(codeobject,__name__)(1,argv,0);
|
||||
if (!IS_STRING(s)) return NONE_VAL();
|
||||
@ -288,15 +303,18 @@ KRK_Method(codeobject,__args__) {
|
||||
return OBJECT_VAL(tuple);
|
||||
}
|
||||
|
||||
KRK_Method(codeobject,__file__) {
|
||||
ATTRIBUTE_NOT_ASSIGNABLE();
|
||||
return self->chunk.filename ? OBJECT_VAL(self->chunk.filename) : OBJECT_VAL(S(""));
|
||||
}
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
#define CURRENT_CTYPE KrkBoundMethod*
|
||||
|
||||
/* __init__ here will be called with a dummy instance as argv[0]; avoid
|
||||
* complications with method argument checking by not using KRK_METHOD. */
|
||||
FUNC_SIG(method,__init__) {
|
||||
static __attribute__ ((unused)) const char* _method_name = "__init__";
|
||||
METHOD_TAKES_EXACTLY(2);
|
||||
KRK_StaticMethod(method,__new__) {
|
||||
FUNCTION_TAKES_EXACTLY(3);
|
||||
if (!IS_OBJECT(argv[1])) return krk_runtimeError(vm.exceptions->typeError, "first argument must be a heap object");
|
||||
return OBJECT_VAL(krk_newBoundMethod(argv[2],AS_OBJECT(argv[1])));
|
||||
}
|
||||
@ -316,7 +334,7 @@ KRK_Method(method,_ip_to_line) {
|
||||
return IS_function(OBJECT_VAL(self->method)) ? FUNC_NAME(function,_ip_to_line)(2,(KrkValue[]){OBJECT_VAL(self->method),argv[1]},0) : OBJECT_VAL(S("?"));
|
||||
}
|
||||
|
||||
KRK_Method(method,__str__) {
|
||||
KRK_Method(method,__repr__) {
|
||||
METHOD_TAKES_NONE();
|
||||
KrkValue s = FUNC_NAME(method,__qualname__)(1,argv,0);
|
||||
if (!IS_STRING(s)) s = FUNC_NAME(method,__name__)(1,argv,0);
|
||||
@ -365,31 +383,32 @@ KRK_Method(method,__func__) {
|
||||
|
||||
KRK_Method(method,__self__) {
|
||||
ATTRIBUTE_NOT_ASSIGNABLE();
|
||||
return OBJECT_VAL(self->receiver);
|
||||
return self->receiver;
|
||||
}
|
||||
|
||||
KRK_Function(staticmethod) {
|
||||
FUNCTION_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(0,CLOSURE,KrkClosure*,method);
|
||||
method->obj.flags &= ~(KRK_OBJ_FLAGS_FUNCTION_MASK);
|
||||
method->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
|
||||
return argv[0];
|
||||
KrkObj* method;
|
||||
if (!krk_parseArgs("O!", (const char*[]){"method"}, KRK_BASE_CLASS(function), &method)) return NONE_VAL();
|
||||
method->flags &= ~(KRK_OBJ_FLAGS_FUNCTION_MASK);
|
||||
method->flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
|
||||
return OBJECT_VAL(method);
|
||||
}
|
||||
|
||||
KRK_Function(classmethod) {
|
||||
FUNCTION_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(0,CLOSURE,KrkClosure*,method);
|
||||
method->obj.flags &= ~(KRK_OBJ_FLAGS_FUNCTION_MASK);
|
||||
method->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
|
||||
return argv[0];
|
||||
KrkObj* method;
|
||||
if (!krk_parseArgs("O!", (const char*[]){"method"}, KRK_BASE_CLASS(function), &method)) return NONE_VAL();
|
||||
method->flags &= ~(KRK_OBJ_FLAGS_FUNCTION_MASK);
|
||||
method->flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
|
||||
return OBJECT_VAL(method);
|
||||
}
|
||||
|
||||
_noexport
|
||||
void _createAndBind_functionClass(void) {
|
||||
KrkClass * codeobject = ADD_BASE_CLASS(vm.baseClasses->codeobjectClass, "codeobject", vm.baseClasses->objectClass);
|
||||
codeobject->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_METHOD(codeobject,__init__);
|
||||
BIND_METHOD(codeobject,__str__);
|
||||
codeobject->allocSize = 0;
|
||||
BIND_STATICMETHOD(codeobject,__new__);
|
||||
BIND_METHOD(codeobject,__repr__);
|
||||
BIND_METHOD(codeobject,_ip_to_line);
|
||||
BIND_PROP(codeobject,__constants__);
|
||||
BIND_PROP(codeobject,__name__);
|
||||
@ -400,13 +419,14 @@ void _createAndBind_functionClass(void) {
|
||||
BIND_PROP(codeobject,co_posonlyargcount);
|
||||
BIND_PROP(codeobject,__locals__);
|
||||
BIND_PROP(codeobject,__args__);
|
||||
krk_defineNative(&codeobject->methods, "__repr__", FUNC_NAME(codeobject,__str__));
|
||||
BIND_PROP(codeobject,__file__);
|
||||
krk_finalizeClass(codeobject);
|
||||
|
||||
KrkClass * function = ADD_BASE_CLASS(vm.baseClasses->functionClass, "function", vm.baseClasses->objectClass);
|
||||
function->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_METHOD(function,__init__);
|
||||
BIND_METHOD(function,__str__);
|
||||
function->allocSize = 0;
|
||||
BIND_STATICMETHOD(function,__new__);
|
||||
BIND_METHOD(function,__repr__);
|
||||
BIND_METHOD(function,_ip_to_line);
|
||||
BIND_PROP(function,__doc__);
|
||||
BIND_PROP(function,__name__);
|
||||
@ -416,15 +436,16 @@ void _createAndBind_functionClass(void) {
|
||||
BIND_PROP(function,__annotations__);
|
||||
BIND_PROP(function,__code__);
|
||||
BIND_PROP(function,__globals__);
|
||||
krk_defineNative(&function->methods, "__repr__", FUNC_NAME(function,__str__));
|
||||
BIND_PROP(function,__closure__);
|
||||
krk_defineNative(&function->methods, "__class_getitem__", krk_GenericAlias)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
|
||||
krk_finalizeClass(function);
|
||||
|
||||
KrkClass * method = ADD_BASE_CLASS(vm.baseClasses->methodClass, "method", vm.baseClasses->objectClass);
|
||||
method->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_METHOD(method,__str__);
|
||||
method->allocSize = 0;
|
||||
BIND_STATICMETHOD(method,__new__);
|
||||
BIND_METHOD(method,__repr__);
|
||||
BIND_METHOD(method,_ip_to_line);
|
||||
BIND_METHOD(method,__init__);
|
||||
BIND_PROP(method,__doc__);
|
||||
BIND_PROP(method,__name__);
|
||||
BIND_PROP(method,__qualname__);
|
||||
@ -434,7 +455,6 @@ void _createAndBind_functionClass(void) {
|
||||
BIND_PROP(method,__self__);
|
||||
BIND_PROP(method,__func__);
|
||||
BIND_PROP(method,__code__);
|
||||
krk_defineNative(&method->methods, "__repr__", FUNC_NAME(method,__str__));
|
||||
krk_finalizeClass(method);
|
||||
|
||||
BUILTIN_FUNCTION("staticmethod", FUNC_NAME(krk,staticmethod), "A static method does not take an implicit self or cls argument.");
|
||||
|
@ -272,6 +272,5 @@ void _createAndBind_generatorClass(void) {
|
||||
BIND_METHOD(generator,__finish__);
|
||||
BIND_METHOD(generator,send);
|
||||
BIND_PROP(generator,gi_running);
|
||||
krk_defineNative(&generator->methods, "__str__", FUNC_NAME(generator,__repr__));
|
||||
krk_finalizeClass(generator);
|
||||
}
|
||||
|
379
src/obj_list.c
379
src/obj_list.c
@ -34,7 +34,7 @@ KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw) {
|
||||
|
||||
if (argc) {
|
||||
AS_LIST(outList)->capacity = argc;
|
||||
AS_LIST(outList)->values = GROW_ARRAY(KrkValue, AS_LIST(outList)->values, 0, argc);
|
||||
AS_LIST(outList)->values = KRK_GROW_ARRAY(KrkValue, AS_LIST(outList)->values, 0, argc);
|
||||
memcpy(AS_LIST(outList)->values, argv, sizeof(KrkValue) * argc);
|
||||
AS_LIST(outList)->count = argc;
|
||||
}
|
||||
@ -138,15 +138,7 @@ KRK_Method(list,__repr__) {
|
||||
pushStringBuilder(&sb, '[');
|
||||
pthread_rwlock_rdlock(&self->rwlock);
|
||||
for (size_t i = 0; i < self->values.count; ++i) {
|
||||
/* repr(self[i]) */
|
||||
KrkClass * type = krk_getType(self->values.values[i]);
|
||||
krk_push(self->values.values[i]);
|
||||
KrkValue result = krk_callDirect(type->_reprer, 1);
|
||||
|
||||
if (IS_STRING(result)) {
|
||||
pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
|
||||
}
|
||||
|
||||
if (!krk_pushStringBuilderFormat(&sb,"%R",self->values.values[i])) goto _error;
|
||||
if (i + 1 < self->values.count) {
|
||||
pushStringBuilderStr(&sb, ", ", 2);
|
||||
}
|
||||
@ -156,14 +148,20 @@ KRK_Method(list,__repr__) {
|
||||
pushStringBuilder(&sb,']');
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return finishStringBuilder(&sb);
|
||||
|
||||
_error:
|
||||
krk_discardStringBuilder(&sb);
|
||||
pthread_rwlock_unlock(&self->rwlock);
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
static int _list_extend_callback(void * context, const KrkValue * values, size_t count) {
|
||||
KrkValueArray * positionals = context;
|
||||
if (positionals->count + count > positionals->capacity) {
|
||||
size_t old = positionals->capacity;
|
||||
positionals->capacity = (count == 1) ? GROW_CAPACITY(old) : (positionals->count + count);
|
||||
positionals->values = GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
|
||||
positionals->capacity = (count == 1) ? KRK_GROW_CAPACITY(old) : (positionals->count + count);
|
||||
positionals->values = KRK_GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
@ -195,7 +193,7 @@ KRK_Method(list,__init__) {
|
||||
if (argc == 2) {
|
||||
_list_extend(2,(KrkValue[]){argv[0],argv[1]},0);
|
||||
}
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(list,__mul__) {
|
||||
@ -306,7 +304,7 @@ KRK_Method(list,__delitem__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
|
||||
if (IS_INTEGER(argv[1])) {
|
||||
FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0],INTEGER_VAL(argv[1])},0);
|
||||
FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0],argv[1]},0);
|
||||
} else if (IS_slice(argv[1])) {
|
||||
KRK_SLICER(argv[1],self->values.count) {
|
||||
return NONE_VAL();
|
||||
@ -416,36 +414,338 @@ KRK_Method(list,copy) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @brief In-place reverse a value array. */
|
||||
static void reverse_values(KrkValue * values, size_t n) {
|
||||
KrkValue * end = values + n - 1;
|
||||
while (values < end) {
|
||||
krk_currentThread.scratchSpace[0] = *values;
|
||||
*values = *end;
|
||||
*end = krk_currentThread.scratchSpace[0];
|
||||
values++;
|
||||
end--;
|
||||
}
|
||||
krk_currentThread.scratchSpace[0] = NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(list,reverse) {
|
||||
METHOD_TAKES_NONE();
|
||||
pthread_rwlock_wrlock(&self->rwlock);
|
||||
for (size_t i = 0; i < (self->values.count) / 2; i++) {
|
||||
KrkValue tmp = self->values.values[i];
|
||||
self->values.values[i] = self->values.values[self->values.count-i-1];
|
||||
self->values.values[self->values.count-i-1] = tmp;
|
||||
}
|
||||
if (self->values.count > 1) reverse_values(self->values.values, self->values.count);
|
||||
pthread_rwlock_unlock(&self->rwlock);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
static int _list_sorter(const void * _a, const void * _b) {
|
||||
KrkValue a = *(KrkValue*)_a;
|
||||
KrkValue b = *(KrkValue*)_b;
|
||||
struct SortSlice {
|
||||
KrkValue * keys;
|
||||
KrkValue * values;
|
||||
};
|
||||
|
||||
/* Avoid actually calling the sort function if there's an active exception */
|
||||
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return -1;
|
||||
KrkValue ltComp = krk_operator_lt(a,b);
|
||||
if (IS_NONE(ltComp) || (IS_BOOLEAN(ltComp) && AS_BOOLEAN(ltComp))) return -1;
|
||||
KrkValue gtComp = krk_operator_gt(a,b);
|
||||
if (IS_NONE(gtComp) || (IS_BOOLEAN(gtComp) && AS_BOOLEAN(gtComp))) return 1;
|
||||
return 0;
|
||||
struct SliceAndPower {
|
||||
struct SortSlice begin;
|
||||
size_t power;
|
||||
};
|
||||
|
||||
struct Run {
|
||||
struct SortSlice start;
|
||||
struct SortSlice end;
|
||||
size_t power;
|
||||
};
|
||||
|
||||
/** @brief s++ */
|
||||
static inline void slice_advance(struct SortSlice * slice) {
|
||||
slice->keys++;
|
||||
if (slice->values) slice->values++;
|
||||
}
|
||||
|
||||
/** @brief s-- */
|
||||
static inline void slice_decrement(struct SortSlice * slice) {
|
||||
slice->keys--;
|
||||
if (slice->values) slice->values--;
|
||||
}
|
||||
|
||||
|
||||
/* @brief s + 1 */
|
||||
static struct SortSlice slice_next(struct SortSlice slice) {
|
||||
return (struct SortSlice){slice.keys + 1, slice.values ? slice.values + 1 : NULL};
|
||||
}
|
||||
|
||||
/** @brief s + n */
|
||||
static struct SortSlice slice_plus(struct SortSlice slice, ssize_t n) {
|
||||
return (struct SortSlice){slice.keys + n, slice.values ? slice.values + n : NULL};
|
||||
}
|
||||
|
||||
/** @brief Copy start-end to buffer */
|
||||
static void copy_slice(struct SortSlice start, struct SortSlice end, struct SortSlice buffer) {
|
||||
while (start.keys != end.keys) {
|
||||
*buffer.keys = *start.keys;
|
||||
if (buffer.values) *buffer.values = *start.values;
|
||||
slice_advance(&start);
|
||||
slice_advance(&buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Very strictly a < b */
|
||||
static int _list_sorter(KrkValue a, KrkValue b) {
|
||||
KrkValue comp = krk_operator_lt(a,b);
|
||||
return (IS_NONE(comp) || (IS_BOOLEAN(comp) && AS_BOOLEAN(comp)));
|
||||
}
|
||||
|
||||
/** @brief While next is strictly < current, advance current */
|
||||
static struct SortSlice powersort_strictlyDecreasingPrefix(struct SortSlice begin, struct SortSlice end) {
|
||||
while (begin.keys + 1 < end.keys && _list_sorter(*(begin.keys + 1), *begin.keys)) slice_advance(&begin);
|
||||
return slice_next(begin);
|
||||
}
|
||||
|
||||
/** @brief While next is greater than or equal to current, advance current */
|
||||
static struct SortSlice powersort_weaklyIncreasingPrefix(struct SortSlice begin, struct SortSlice end) {
|
||||
while (begin.keys + 1 < end.keys && !_list_sorter(*(begin.keys + 1), *begin.keys)) slice_advance(&begin);
|
||||
return slice_next(begin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extend a run to the right
|
||||
*
|
||||
* Returns a slice pointing at the end of the run after extended it to the right.
|
||||
* The resulting run consists of strictly ordered (a <= b, b > a) entries. We also
|
||||
* handle reverse runs by reversing them in-place.
|
||||
*
|
||||
* @param begin Start of run
|
||||
* @param end End of available input to scan; always end of list.
|
||||
* @returns Slice pointing to end of run
|
||||
*/
|
||||
static struct SortSlice powersort_extend_and_reverse_right(struct SortSlice begin, struct SortSlice end) {
|
||||
struct SortSlice j = begin;
|
||||
if (j.keys == end.keys) return j;
|
||||
if (j.keys + 1 == end.keys) return slice_next(j);
|
||||
if (_list_sorter(*slice_next(j).keys, *j.keys)) {
|
||||
/* If next is strictly less than current, begin a reversed chain; we already know
|
||||
* we can advance by one, so do that before continuing to save a comparison. */
|
||||
j = powersort_strictlyDecreasingPrefix(slice_next(begin), end);
|
||||
reverse_values(begin.keys, j.keys - begin.keys);
|
||||
if (begin.values) reverse_values(begin.values, j.values - begin.values);
|
||||
} else {
|
||||
/* Weakly increasing means j+1 >= j; continue with that chain*/
|
||||
j = powersort_weaklyIncreasingPrefix(slice_next(begin), end);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate power.
|
||||
*
|
||||
* I'll be honest here, I don't really know what this does; it's from the reference impl.
|
||||
* and described in the paper.
|
||||
*/
|
||||
static size_t powersort_power(size_t begin, size_t end, size_t beginA, size_t beginB, size_t endB) {
|
||||
size_t n = end - begin;
|
||||
unsigned long l = beginA - begin + beginB - begin;
|
||||
unsigned long r = beginB - begin + endB - begin;
|
||||
size_t common = 0;
|
||||
int digitA = l >= n;
|
||||
int digitB = r >= n;
|
||||
while (digitA == digitB) {
|
||||
common++;
|
||||
if (digitA) {
|
||||
l -= n;
|
||||
r -= n;
|
||||
}
|
||||
l <<= 1;
|
||||
r <<= 1;
|
||||
digitA = l >= n;
|
||||
digitB = r >= n;
|
||||
}
|
||||
return common + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Merge neighboring runs.
|
||||
*
|
||||
* Merges the neighboring, sorted runs [left, mid) and [mid, right) using the provided
|
||||
* buffer space. Specifically, the smaller of the two runs is copied to the buffer, and
|
||||
* then merging occurs in-place.
|
||||
*
|
||||
* @param left Start of the first run
|
||||
* @param mid End of first run, start of second run
|
||||
* @param right End of second run
|
||||
* @param buffer Scratch space
|
||||
*/
|
||||
static void powersort_merge(struct SortSlice left, struct SortSlice mid, struct SortSlice right, struct SortSlice buffer) {
|
||||
size_t n1 = mid.keys - left.keys;
|
||||
size_t n2 = right.keys - mid.keys;
|
||||
|
||||
if (n1 <= n2) {
|
||||
copy_slice(left, mid, buffer);
|
||||
struct SortSlice c1 = buffer, e1 = slice_plus(buffer, n1);
|
||||
struct SortSlice c2 = mid, e2 = right, o = left;
|
||||
|
||||
while (c1.keys < e1.keys && c2.keys < e2.keys) {
|
||||
if (!_list_sorter(*c2.keys, *c1.keys)) {
|
||||
*o.keys = *c1.keys;
|
||||
if (o.values) *o.values = *c1.values;
|
||||
slice_advance(&c1);
|
||||
} else {
|
||||
*o.keys = *c2.keys;
|
||||
if (o.values) *o.values = *c2.values;
|
||||
slice_advance(&c2);
|
||||
}
|
||||
slice_advance(&o);
|
||||
}
|
||||
|
||||
while (c1.keys < e1.keys) {
|
||||
*o.keys = *c1.keys;
|
||||
if (o.values) *o.values = *c1.values;
|
||||
slice_advance(&c1);
|
||||
slice_advance(&o);
|
||||
}
|
||||
} else {
|
||||
copy_slice(mid, right, buffer);
|
||||
|
||||
struct SortSlice c1 = slice_plus(mid, -1), s1 = left, o = slice_plus(right, -1);
|
||||
struct SortSlice c2 = slice_plus(buffer, n2 - 1), s2 = buffer;
|
||||
|
||||
while (c1.keys >= s1.keys && c2.keys >= s2.keys) {
|
||||
if (!_list_sorter(*c2.keys, *c1.keys)) {
|
||||
*o.keys = *c2.keys;
|
||||
if (o.values) *o.values = *c2.values;
|
||||
slice_decrement(&c2);
|
||||
} else {
|
||||
*o.keys = *c1.keys;
|
||||
if (o.values) *o.values = *c1.values;
|
||||
slice_decrement(&c1);
|
||||
}
|
||||
slice_decrement(&o);
|
||||
}
|
||||
|
||||
while (c2.keys >= s2.keys) {
|
||||
*o.keys = *c2.keys;
|
||||
if (o.values) *o.values = *c2.values;
|
||||
slice_decrement(&c2);
|
||||
slice_decrement(&o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Powersort - merge-sort sorted runs
|
||||
*
|
||||
* This is an implementation of Munro-Wild Powersort from the paper at:
|
||||
* @ref https://www.wild-inter.net/publications/html/munro-wild-2018.pdf.html
|
||||
*
|
||||
* The reference implementation was also a helpful thing to study, and much
|
||||
* of the iteration and merging is based on its use of C++ iterators:
|
||||
* @ref https://github.com/sebawild/powersort
|
||||
*
|
||||
* There's no fancy extensions or improvements here, just the plain approach
|
||||
* set out in the paper, which is probably good enough for us? That means no
|
||||
* extending short runs to a minimum run length, no fancy node power calcs,
|
||||
* just a short bit of extending and merging.
|
||||
*
|
||||
* If the key function raises an exception, no sorting will be attempted
|
||||
* and the exception from the key function will be raised immediately.
|
||||
*
|
||||
* If the values to be sorted can not compare with __lt__, an exception
|
||||
* should be thrown eventually, but the entire list may still be scanned
|
||||
* and the resulting state is undefined.
|
||||
*
|
||||
* @param list List to sort in-place.
|
||||
* @param key Key function, or None to sort values directly.
|
||||
* @param reverse Sort direction, 0 for normal (a[0] <= b[0], etc.), 1 for reversed.
|
||||
*/
|
||||
static void powersort(KrkList * list, KrkValue key, int reverse) {
|
||||
size_t n = list->values.count;
|
||||
struct SortSlice slice = {list->values.values, NULL};
|
||||
|
||||
/* If there is a key function, create a separate array to store
|
||||
* the resulting key values; shove it in a tuple so we can keep
|
||||
* those key values from being garbage collected. */
|
||||
if (!IS_NONE(key)) {
|
||||
KrkTuple * _keys = krk_newTuple(n);
|
||||
krk_push(OBJECT_VAL(_keys));
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
krk_push(key);
|
||||
krk_push(list->values.values[i]);
|
||||
_keys->values.values[i] = krk_callStack(1);
|
||||
_keys->values.count++;
|
||||
|
||||
/* If the key function threw an exception, bail early. */
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _end_sort;
|
||||
}
|
||||
|
||||
/* values are secondary, keys are what actually gets sorted */
|
||||
slice.values = slice.keys;
|
||||
slice.keys = _keys->values.values;
|
||||
}
|
||||
|
||||
/* We handle reverse sort by reversing, sorting normally, and then reversing again */
|
||||
if (reverse) {
|
||||
reverse_values(slice.keys, n);
|
||||
if (slice.values) reverse_values(slice.values, n);
|
||||
}
|
||||
|
||||
/* Supposedly the absolute maximum for this is strictly less than the number of bits
|
||||
* we can fit in a size_t, so 64 ought to cover us until someone tries porting Kuroko
|
||||
* to one of the 128-bit architectures, but even then I don't think we can handle
|
||||
* holding that many values in a list to begin with.
|
||||
*
|
||||
* stack[0] should always be empty. */
|
||||
struct SliceAndPower stack[64] = {0};
|
||||
int top = 0;
|
||||
|
||||
/* Buffer space for the merges. We shouldn't need anywhere close to this much space,
|
||||
* but best to be safe, and we're already allocating a bunch of space for key tuples */
|
||||
KrkTuple * bufferSpace = krk_newTuple(slice.values ? (n * 2) : n);
|
||||
krk_push(OBJECT_VAL(bufferSpace));
|
||||
for (size_t i = 0; i < bufferSpace->values.capacity; ++i) bufferSpace->values.values[bufferSpace->values.count++] = NONE_VAL();
|
||||
struct SortSlice buffer = {&bufferSpace->values.values[0], slice.values ? &bufferSpace->values.values[n] : NULL};
|
||||
|
||||
/* This just take the role of the C++ iterators in the reference implementaiton */
|
||||
struct SortSlice begin = {slice.keys, slice.values};
|
||||
struct SortSlice end = {slice.keys + n, slice.values ? slice.values + n : NULL};
|
||||
|
||||
/* Our first run starts from the left and extends as far as it can. */
|
||||
struct Run a = {begin, powersort_extend_and_reverse_right(begin,end), 0};
|
||||
|
||||
while (a.end.keys < end.keys) {
|
||||
/* Our next run is whatever is after that, assuming the initial run isn't the whole list. */
|
||||
struct Run b = {a.end, powersort_extend_and_reverse_right(a.end, end), 0};
|
||||
/* I don't really understand the power part of powersort, but whatever. */
|
||||
a.power = powersort_power(0, n, a.start.keys - begin.keys, b.start.keys - begin.keys, b.end.keys - begin.keys);
|
||||
|
||||
/* While the stack has things with higher power, merge them into a */
|
||||
while (stack[top].power > a.power) {
|
||||
struct SliceAndPower top_run = stack[top--];
|
||||
powersort_merge(top_run.begin, a.start, a.end, buffer);
|
||||
a.start = top_run.begin;
|
||||
}
|
||||
/* Put a on top of the stack, and then replace a with b */
|
||||
stack[++top] = (struct SliceAndPower){a.start, a.power};
|
||||
a = (struct Run){b.start, b.end, 0};
|
||||
}
|
||||
|
||||
/* While there are things in the stack (excluding the empty 0 slot), merge them into the last a */
|
||||
while (top > 0) {
|
||||
struct SliceAndPower top_run = stack[top--];
|
||||
powersort_merge(top_run.begin, a.start, end, buffer);
|
||||
a.start = top_run.begin;
|
||||
}
|
||||
|
||||
krk_pop(); /* tuple with buffer space */
|
||||
_end_sort:
|
||||
if (!IS_NONE(key)) krk_pop(); /* keys tuple */
|
||||
|
||||
/* If we reversed at the start, reverse again now as the list is forward-sorted */
|
||||
if (reverse) reverse_values(list->values.values, n);
|
||||
}
|
||||
|
||||
KRK_Method(list,sort) {
|
||||
METHOD_TAKES_NONE();
|
||||
KrkValue key = NONE_VAL();
|
||||
int reverse = 0;
|
||||
if (!krk_parseArgs(".|$Vp", (const char*[]){"key","reverse"}, &key, &reverse)) return NONE_VAL();
|
||||
|
||||
if (self->values.count < 2) return NONE_VAL();
|
||||
|
||||
pthread_rwlock_wrlock(&self->rwlock);
|
||||
qsort(self->values.values, self->values.count, sizeof(KrkValue), _list_sorter);
|
||||
powersort(self, key, reverse);
|
||||
pthread_rwlock_unlock(&self->rwlock);
|
||||
|
||||
return NONE_VAL();
|
||||
@ -517,11 +817,11 @@ KRK_Method(listiterator,__init__) {
|
||||
CHECK_ARG(1,list,KrkList*,list);
|
||||
self->l = argv[1];
|
||||
self->i = 0;
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
FUNC_SIG(listiterator,__call__) {
|
||||
static __attribute__ ((unused)) const char* _method_name = "__call__";
|
||||
static _unused const char* _method_name = "__call__";
|
||||
if (unlikely((argc != 1))) goto _bad;
|
||||
if (unlikely(!IS_OBJECT(argv[0]))) goto _bad;
|
||||
if (unlikely(AS_INSTANCE(argv[0])->_class != vm.baseClasses->listiteratorClass)) goto _bad;
|
||||
@ -544,18 +844,18 @@ _bad:
|
||||
goto _maybeGood;
|
||||
}
|
||||
|
||||
static KrkValue _sorted(int argc, const KrkValue argv[], int hasKw) {
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError,"%s() takes %s %d argument%s (%d given)","sorted","exactly",1,"",argc);
|
||||
KRK_Function(sorted) {
|
||||
if (argc < 1) return krk_runtimeError(vm.exceptions->argumentError,"%s() takes %s %d argument%s (%d given)","sorted","at least",1,"",argc);
|
||||
KrkValue listOut = krk_list_of(0,NULL,0);
|
||||
krk_push(listOut);
|
||||
FUNC_NAME(list,extend)(2,(KrkValue[]){listOut,argv[0]},0);
|
||||
if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL();
|
||||
FUNC_NAME(list,sort)(1,&listOut,0);
|
||||
FUNC_NAME(list,sort)(1,(KrkValue[]){listOut,hasKw ? argv[1] : NONE_VAL(), hasKw ? argv[2] : NONE_VAL()},hasKw);
|
||||
if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL();
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
static KrkValue _reversed(int argc, const KrkValue argv[], int hasKw) {
|
||||
KRK_Function(reversed) {
|
||||
/* FIXME The Python reversed() function produces an iterator and only works for things with indexing or a __reversed__ method;
|
||||
* Building a list and reversing it like we do here is not correct! */
|
||||
if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError,"%s() takes %s %d argument%s (%d given)","reversed","exactly",1,"",argc);
|
||||
@ -640,17 +940,16 @@ void _createAndBind_listClass(void) {
|
||||
"@brief Sort the contents of a list.\n\n"
|
||||
"Performs an in-place sort of the elements in the list, returning @c None as a gentle reminder "
|
||||
"that the sort is in-place. If a sorted copy is desired, use @ref sorted instead.");
|
||||
krk_defineNative(&list->methods, "__str__", FUNC_NAME(list,__repr__));
|
||||
krk_defineNative(&list->methods, "__class_getitem__", krk_GenericAlias)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
|
||||
krk_attachNamedValue(&list->methods, "__hash__", NONE_VAL());
|
||||
krk_finalizeClass(list);
|
||||
KRK_DOC(list, "Mutable sequence of arbitrary values.");
|
||||
|
||||
BUILTIN_FUNCTION("sorted", _sorted,
|
||||
BUILTIN_FUNCTION("sorted", FUNC_NAME(krk,sorted),
|
||||
"@brief Return a sorted representation of an iterable.\n"
|
||||
"@arguments iterable\n\n"
|
||||
"Creates a new, sorted list from the elements of @p iterable.");
|
||||
BUILTIN_FUNCTION("reversed", _reversed,
|
||||
BUILTIN_FUNCTION("reversed", FUNC_NAME(krk,reversed),
|
||||
"@brief Return a reversed representation of an iterable.\n"
|
||||
"@arguments iterable\n\n"
|
||||
"Creates a new, reversed list from the elements of @p iterable.");
|
||||
|
1369
src/obj_long.c
1369
src/obj_long.c
File diff suppressed because it is too large
Load Diff
@ -16,39 +16,69 @@
|
||||
|
||||
extern KrkValue krk_int_from_float(double val);
|
||||
|
||||
FUNC_SIG(int,__init__) {
|
||||
static __attribute__ ((unused)) const char* _method_name = "__init__";
|
||||
METHOD_TAKES_AT_MOST(2);
|
||||
if (argc < 2) return INTEGER_VAL(0);
|
||||
if (IS_BOOLEAN(argv[1])) return INTEGER_VAL(AS_INTEGER(argv[1]));
|
||||
if (IS_INTEGER(argv[1])) return argv[1];
|
||||
if (IS_STRING(argv[1])) {
|
||||
krk_integer_type _base = 10;
|
||||
if (argc > 2) {
|
||||
CHECK_ARG(2,int,krk_integer_type,base);
|
||||
_base = base;
|
||||
}
|
||||
if (unlikely(_base < 0 || _base == 1 || _base > 36)) return krk_runtimeError(vm.exceptions->valueError, "base must be 0 or between 2 and 36");
|
||||
KrkValue result = krk_parse_int(AS_CSTRING(argv[1]), AS_STRING(argv[1])->length, _base);
|
||||
KRK_StaticMethod(int,__new__) {
|
||||
KrkObj *cls;
|
||||
int has_x = 0;
|
||||
KrkValue x = NONE_VAL();
|
||||
int has_base = 0;
|
||||
int base = 10;
|
||||
|
||||
/* Most common case */
|
||||
if (!hasKw && argc == 2) {
|
||||
x = argv[1];
|
||||
goto _just_x;
|
||||
}
|
||||
|
||||
if (!krk_parseArgs("O|V?i?:int", (const char*[]){"","","base"},
|
||||
&cls, &has_x, &x, &has_base, &base)) return NONE_VAL();
|
||||
|
||||
if (has_base && (base < 2 || base > 36) && base != 0) {
|
||||
return krk_runtimeError(vm.exceptions->valueError, "base must be 0 or between 2 and 36");
|
||||
}
|
||||
|
||||
if (!has_x && has_base) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "missing str argument");
|
||||
}
|
||||
|
||||
if (!has_x) {
|
||||
return INTEGER_VAL(0);
|
||||
}
|
||||
|
||||
if (has_base && !IS_STRING(x)) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "can not convert non-str with explicit base");
|
||||
}
|
||||
|
||||
_just_x:
|
||||
|
||||
if (IS_INTEGER(x)) return INTEGER_VAL(AS_INTEGER(x));
|
||||
#ifndef KRK_NO_FLOAT
|
||||
if (IS_FLOATING(x)) return krk_int_from_float(AS_FLOATING(x));
|
||||
#endif
|
||||
|
||||
if (IS_STRING(x)) {
|
||||
KrkValue result = krk_parse_int(AS_CSTRING(x), AS_STRING(x)->length, base);
|
||||
if (IS_NONE(result)) {
|
||||
return krk_runtimeError(vm.exceptions->valueError,
|
||||
"invalid literal for int() with base %zd: %R", (ssize_t)_base, argv[1]);
|
||||
"invalid literal for int() with base %zd: %R", (ssize_t)base, x);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (IS_FLOATING(argv[1])) return krk_int_from_float(AS_FLOATING(argv[1]));
|
||||
if (IS_BOOLEAN(argv[1])) return INTEGER_VAL(AS_BOOLEAN(argv[1]));
|
||||
return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "int", argv[1]);
|
||||
|
||||
if (krk_isInstanceOf(x, KRK_BASE_CLASS(long))) return x;
|
||||
return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "int", x);
|
||||
}
|
||||
|
||||
KRK_Method(int,__str__) {
|
||||
KRK_Method(int,__repr__) {
|
||||
char tmp[100];
|
||||
size_t l = snprintf(tmp, 100, PRIkrk_int, self);
|
||||
return OBJECT_VAL(krk_copyString(tmp, l));
|
||||
}
|
||||
|
||||
KRK_Method(int,__int__) { return argv[0]; }
|
||||
|
||||
#ifndef KRK_NO_FLOAT
|
||||
KRK_Method(int,__float__) { return FLOATING_VAL(self); }
|
||||
#endif
|
||||
|
||||
KRK_Method(int,__chr__) {
|
||||
unsigned char bytes[5] = {0};
|
||||
@ -59,7 +89,9 @@ KRK_Method(int,__chr__) {
|
||||
KRK_Method(int,__eq__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
if (likely(IS_INTEGER(argv[1]))) return BOOLEAN_VAL(self == AS_INTEGER(argv[1]));
|
||||
#ifndef KRK_NO_FLOAT
|
||||
else if (IS_FLOATING(argv[1])) return BOOLEAN_VAL(self == AS_FLOATING(argv[1]));
|
||||
#endif
|
||||
return NOTIMPL_VAL();
|
||||
}
|
||||
|
||||
@ -211,7 +243,7 @@ KrkValue krk_doFormatString(const char * typeName, KrkString * format_spec, int
|
||||
if ((!positive || opts.sign == '+') && width > 1) width--;
|
||||
|
||||
int digits = 0;
|
||||
int sepcount = opts.sep == ',' ? 3 : 4;
|
||||
int sepcount = (opts.sep == ',' || base == 10) ? 3 : 4;
|
||||
int more = 0;
|
||||
|
||||
if (prepCallback) callback = prepCallback(abs, base);
|
||||
@ -337,15 +369,21 @@ OVERFLOW_CHECKED_INT_OPERATION(add,+)
|
||||
OVERFLOW_CHECKED_INT_OPERATION(sub,-)
|
||||
OVERFLOW_CHECKED_INT_OPERATION(mul,*)
|
||||
|
||||
#ifndef KRK_NO_FLOAT
|
||||
# define MAYBE_FLOAT(x) x
|
||||
#else
|
||||
# define MAYBE_FLOAT(x) krk_runtimeError(vm.exceptions->valueError, "no float support")
|
||||
#endif
|
||||
|
||||
#define BASIC_BIN_OP(name,operator) \
|
||||
KRK_Method(int,__ ## name ## __) { \
|
||||
if (likely(IS_INTEGER(argv[1]))) return krk_int_op_ ## name(self, AS_INTEGER(argv[1])); \
|
||||
else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL((double)self operator AS_FLOATING(argv[1])); \
|
||||
else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(FLOATING_VAL((double)self operator AS_FLOATING(argv[1]))); \
|
||||
return NOTIMPL_VAL(); \
|
||||
} \
|
||||
KRK_Method(int,__r ## name ## __) { \
|
||||
if (likely(IS_INTEGER(argv[1]))) return krk_int_op_ ## name(AS_INTEGER(argv[1]), self); \
|
||||
else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(AS_FLOATING(argv[1]) operator (double)self); \
|
||||
else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(FLOATING_VAL(AS_FLOATING(argv[1]) operator (double)self)); \
|
||||
return NOTIMPL_VAL(); \
|
||||
}
|
||||
|
||||
@ -362,7 +400,7 @@ OVERFLOW_CHECKED_INT_OPERATION(mul,*)
|
||||
#define COMPARE_OP(name,operator) \
|
||||
KRK_Method(int,__ ## name ## __) { \
|
||||
if (likely(IS_INTEGER(argv[1]))) return BOOLEAN_VAL(self operator AS_INTEGER(argv[1])); \
|
||||
else if (likely(IS_FLOATING(argv[1]))) return BOOLEAN_VAL((double)self operator AS_FLOATING(argv[1])); \
|
||||
else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(BOOLEAN_VAL((double)self operator AS_FLOATING(argv[1]))); \
|
||||
return NOTIMPL_VAL(); \
|
||||
}
|
||||
|
||||
@ -397,6 +435,7 @@ COMPARE_OP(ge, >=)
|
||||
#undef INT_ONLY_BIN_OP
|
||||
#undef COMPARE_OP
|
||||
|
||||
#ifndef KRK_NO_FLOAT
|
||||
KRK_Method(int,__truediv__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
if (likely(IS_INTEGER(argv[1]))) {
|
||||
@ -418,6 +457,7 @@ KRK_Method(int,__rtruediv__) {
|
||||
else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(AS_FLOATING(argv[1]) / (double)self);
|
||||
return NOTIMPL_VAL();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __TINYC__
|
||||
#include <math.h>
|
||||
@ -477,9 +517,13 @@ KRK_Method(int,__floordiv__) {
|
||||
if (likely(IS_INTEGER(argv[1]))) {
|
||||
return _krk_int_div(self,AS_INTEGER(argv[1]));
|
||||
} else if (likely(IS_FLOATING(argv[1]))) {
|
||||
#ifndef KRK_NO_FLOAT
|
||||
double b = AS_FLOATING(argv[1]);
|
||||
if (unlikely(b == 0.0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "float division by zero");
|
||||
return FLOATING_VAL(__builtin_floor((double)self / b));
|
||||
#else
|
||||
return krk_runtimeError(vm.exceptions->valueError, "no float support");
|
||||
#endif
|
||||
}
|
||||
return NOTIMPL_VAL();
|
||||
}
|
||||
@ -488,7 +532,7 @@ KRK_Method(int,__rfloordiv__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
if (unlikely(self == 0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "integer division by zero");
|
||||
else if (likely(IS_INTEGER(argv[1]))) return _krk_int_div(AS_INTEGER(argv[1]), self);
|
||||
else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(__builtin_floor(AS_FLOATING(argv[1]) / (double)self));
|
||||
else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(FLOATING_VAL(__builtin_floor(AS_FLOATING(argv[1]) / (double)self)));
|
||||
return NOTIMPL_VAL();
|
||||
}
|
||||
|
||||
@ -567,9 +611,9 @@ KRK_Method(int,__pos__) {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
FUNC_SIG(float,__init__) {
|
||||
static __attribute__ ((unused)) const char* _method_name = "__init__";
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
#ifndef KRK_NO_FLOAT
|
||||
KRK_StaticMethod(float,__new__) {
|
||||
FUNCTION_TAKES_AT_MOST(2);
|
||||
if (argc < 2) return FLOATING_VAL(0.0);
|
||||
if (IS_FLOATING(argv[1])) return argv[1];
|
||||
if (IS_INTEGER(argv[1])) return FLOATING_VAL(AS_INTEGER(argv[1]));
|
||||
@ -580,24 +624,94 @@ FUNC_SIG(float,__init__) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "float", argv[1]);
|
||||
}
|
||||
|
||||
KRK_Method(float,__int__) { return INTEGER_VAL(self); }
|
||||
KRK_Method(float,__int__) { return krk_int_from_float(self); }
|
||||
KRK_Method(float,__float__) { return argv[0]; }
|
||||
|
||||
static int isDigits(const char * c) {
|
||||
while (*c) {
|
||||
if (*c != '-' && (*c < '0' || *c > '9')) return 0;
|
||||
c++;
|
||||
}
|
||||
return 1;
|
||||
extern KrkValue krk_double_to_string(double,unsigned int,char,int,int);
|
||||
KRK_Method(float,__repr__) {
|
||||
return krk_double_to_string(self,16,' ',0,0);
|
||||
}
|
||||
|
||||
KRK_Method(float,__str__) {
|
||||
char tmp[100];
|
||||
size_t l = snprintf(tmp, 97, "%.16g", self);
|
||||
if (!strstr(tmp,".") && isDigits(tmp)) {
|
||||
l = snprintf(tmp,100,"%.16g.0",self);
|
||||
KRK_Method(float,__format__) {
|
||||
char * format_spec;
|
||||
size_t format_spec_length;
|
||||
if (!krk_parseArgs(".s#", (const char*[]){"format_spec"}, &format_spec, &format_spec_length)) return NONE_VAL();
|
||||
|
||||
struct ParsedFormatSpec opts = {0};
|
||||
const char * spec = krk_parseCommonFormatSpec(&opts, format_spec, format_spec_length);
|
||||
if (!spec) return NONE_VAL();
|
||||
|
||||
char formatter = 'g';
|
||||
int digits = 16;
|
||||
int forcedigits = opts.alt;
|
||||
|
||||
switch (*spec) {
|
||||
case 0:
|
||||
case 'g':
|
||||
/* defaults */
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
formatter = 'G';
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'e':
|
||||
case 'E':
|
||||
digits = 6;
|
||||
formatter = *spec;
|
||||
forcedigits = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return krk_runtimeError(vm.exceptions->valueError,
|
||||
"Unknown format code '%c' for object of type '%s'",
|
||||
*spec,
|
||||
"float");
|
||||
}
|
||||
return OBJECT_VAL(krk_copyString(tmp, l));
|
||||
|
||||
if (opts.sep) return krk_runtimeError(vm.exceptions->valueError, "unsupported option for float");
|
||||
if (opts.hasPrecision) digits = opts.prec;
|
||||
if (!opts.align) opts.align = '>';
|
||||
|
||||
KrkValue result = krk_double_to_string(self, digits, formatter, opts.sign == '+', forcedigits);
|
||||
if (!IS_STRING(result) || !opts.width) return result;
|
||||
|
||||
krk_push(result);
|
||||
|
||||
/* Calculate how much padding we need to add. */
|
||||
size_t avail = (size_t)opts.width > AS_STRING(result)->length ? (size_t)opts.width - AS_STRING(result)->length : 0;
|
||||
|
||||
/* If there's no available space for padding, just return the string we already have. */
|
||||
if (!avail) return krk_pop();
|
||||
|
||||
struct StringBuilder sb = {0};
|
||||
size_t before = 0;
|
||||
size_t after = 0;
|
||||
int hassign = 0;
|
||||
if (opts.align == '<') {
|
||||
after = avail;
|
||||
} else if (opts.align == '>') {
|
||||
before = avail;
|
||||
} else if (opts.align == '^') {
|
||||
after = avail / 2;
|
||||
before = avail - after;
|
||||
} else if (opts.align == '=') {
|
||||
before = avail;
|
||||
if (avail && AS_STRING(result)->length && (AS_CSTRING(result)[0] == '-' || AS_CSTRING(result)[0] == '+')) {
|
||||
krk_pushStringBuilder(&sb, AS_CSTRING(result)[0]);
|
||||
hassign = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in padding with a new string builder. */
|
||||
for (size_t i = 0; i < before; ++i) krk_pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
|
||||
krk_pushStringBuilderStr(&sb, AS_CSTRING(result) + hassign, AS_STRING(result)->length - hassign);
|
||||
for (size_t i = 0; i < after; ++i) krk_pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
|
||||
|
||||
krk_pop();
|
||||
return krk_finishStringBuilder(&sb);
|
||||
}
|
||||
|
||||
KRK_Method(float,__eq__) {
|
||||
@ -700,26 +814,42 @@ KRK_Method(float,__pos__) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
extern KrkValue krk_float_to_fraction(double d);
|
||||
KRK_Method(float,as_integer_ratio) {
|
||||
return krk_float_to_fraction(self);
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
#define CURRENT_CTYPE krk_integer_type
|
||||
|
||||
FUNC_SIG(bool,__init__) {
|
||||
static __attribute__ ((unused)) const char* _method_name = "__init__";
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
KRK_StaticMethod(bool,__new__) {
|
||||
FUNCTION_TAKES_AT_MOST(2);
|
||||
if (argc < 2) return BOOLEAN_VAL(0);
|
||||
return BOOLEAN_VAL(!krk_isFalsey(argv[1]));
|
||||
}
|
||||
|
||||
KRK_Method(bool,__str__) {
|
||||
KRK_Method(bool,__repr__) {
|
||||
return OBJECT_VAL((self ? S("True") : S("False")));
|
||||
}
|
||||
|
||||
FUNC_SIG(NoneType,__init__) {
|
||||
KRK_Method(bool,__format__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(1,str,KrkString*,format_spec);
|
||||
|
||||
if (!format_spec->length) {
|
||||
return FUNC_NAME(bool,__repr__)(argc,argv,hasKw);
|
||||
} else {
|
||||
return FUNC_NAME(int,__format__)(argc,argv,hasKw);
|
||||
}
|
||||
}
|
||||
|
||||
KRK_StaticMethod(NoneType,__new__) {
|
||||
if (argc > 1) return krk_runtimeError(vm.exceptions->argumentError, "%s takes no arguments", "NoneType");
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(NoneType,__str__) {
|
||||
KRK_Method(NoneType,__repr__) {
|
||||
return OBJECT_VAL(S("None"));
|
||||
}
|
||||
|
||||
@ -736,12 +866,12 @@ KRK_Method(NoneType,__eq__) {
|
||||
#define IS_NotImplementedType(o) IS_NOTIMPL(o)
|
||||
#define AS_NotImplementedType(o) (1)
|
||||
|
||||
FUNC_SIG(NotImplementedType,__init__) {
|
||||
KRK_StaticMethod(NotImplementedType,__new__) {
|
||||
if (argc > 1) return krk_runtimeError(vm.exceptions->argumentError, "%s takes no arguments", "NotImplementedType");
|
||||
return NOTIMPL_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(NotImplementedType,__str__) {
|
||||
KRK_Method(NotImplementedType,__repr__) {
|
||||
return OBJECT_VAL(S("NotImplemented"));
|
||||
}
|
||||
|
||||
@ -756,8 +886,10 @@ KRK_Method(NotImplementedType,__eq__) {
|
||||
}
|
||||
|
||||
#undef BIND_METHOD
|
||||
#undef BIND_STATICMETHOD
|
||||
/* These class names conflict with C types, so we need to cheat a bit */
|
||||
#define BIND_METHOD(klass,method) do { krk_defineNative(& _ ## klass->methods, #method, _ ## klass ## _ ## method); } while (0)
|
||||
#define BIND_STATICMETHOD(klass,method) do { krk_defineNativeStaticMethod(& _ ## klass->methods, #method, _ ## klass ## _ ## method); } while (0)
|
||||
#define BIND_TRIPLET(klass,name) \
|
||||
BIND_METHOD(klass,__ ## name ## __); \
|
||||
BIND_METHOD(klass,__r ## name ## __); \
|
||||
@ -766,11 +898,11 @@ _noexport
|
||||
void _createAndBind_numericClasses(void) {
|
||||
KrkClass * _int = ADD_BASE_CLASS(vm.baseClasses->intClass, "int", vm.baseClasses->objectClass);
|
||||
_int->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_METHOD(int,__init__);
|
||||
BIND_METHOD(int,__str__);
|
||||
_int->allocSize = 0;
|
||||
BIND_STATICMETHOD(int,__new__);
|
||||
BIND_METHOD(int,__repr__);
|
||||
BIND_METHOD(int,__int__);
|
||||
BIND_METHOD(int,__chr__);
|
||||
BIND_METHOD(int,__float__);
|
||||
BIND_METHOD(int,__eq__);
|
||||
BIND_METHOD(int,__hash__);
|
||||
BIND_METHOD(int,__format__);
|
||||
@ -784,10 +916,14 @@ void _createAndBind_numericClasses(void) {
|
||||
BIND_TRIPLET(int,lshift);
|
||||
BIND_TRIPLET(int,rshift);
|
||||
BIND_TRIPLET(int,mod);
|
||||
BIND_TRIPLET(int,truediv);
|
||||
BIND_TRIPLET(int,floordiv);
|
||||
BIND_TRIPLET(int,pow);
|
||||
|
||||
#ifndef KRK_NO_FLOAT
|
||||
BIND_METHOD(int,__float__);
|
||||
BIND_TRIPLET(int,truediv);
|
||||
#endif
|
||||
|
||||
BIND_METHOD(int,__lt__);
|
||||
BIND_METHOD(int,__gt__);
|
||||
BIND_METHOD(int,__le__);
|
||||
@ -801,16 +937,17 @@ void _createAndBind_numericClasses(void) {
|
||||
BIND_METHOD(int,__abs__);
|
||||
BIND_METHOD(int,__pos__);
|
||||
|
||||
krk_defineNative(&_int->methods, "__repr__", FUNC_NAME(int,__str__));
|
||||
krk_finalizeClass(_int);
|
||||
KRK_DOC(_int, "Convert a number or string type to an integer representation.");
|
||||
|
||||
KrkClass * _float = ADD_BASE_CLASS(vm.baseClasses->floatClass, "float", vm.baseClasses->objectClass);
|
||||
_float->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_METHOD(float,__init__);
|
||||
_float->allocSize = 0;
|
||||
#ifndef KRK_NO_FLOAT
|
||||
BIND_STATICMETHOD(float,__new__);
|
||||
BIND_METHOD(float,__int__);
|
||||
BIND_METHOD(float,__float__);
|
||||
BIND_METHOD(float,__str__);
|
||||
BIND_METHOD(float,__repr__);
|
||||
BIND_METHOD(float,__eq__);
|
||||
BIND_METHOD(float,__hash__);
|
||||
BIND_TRIPLET(float,add);
|
||||
@ -825,34 +962,36 @@ void _createAndBind_numericClasses(void) {
|
||||
BIND_METHOD(float,__neg__);
|
||||
BIND_METHOD(float,__abs__);
|
||||
BIND_METHOD(float,__pos__);
|
||||
krk_defineNative(&_float->methods, "__repr__", FUNC_NAME(float,__str__));
|
||||
BIND_METHOD(float,__format__);
|
||||
BIND_METHOD(float,as_integer_ratio);
|
||||
#endif
|
||||
krk_finalizeClass(_float);
|
||||
KRK_DOC(_float, "Convert a number or string type to a float representation.");
|
||||
|
||||
KrkClass * _bool = ADD_BASE_CLASS(vm.baseClasses->boolClass, "bool", vm.baseClasses->intClass);
|
||||
_bool->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_METHOD(bool,__init__);
|
||||
BIND_METHOD(bool,__str__);
|
||||
krk_defineNative(&_bool->methods, "__repr__", FUNC_NAME(bool,__str__));
|
||||
BIND_STATICMETHOD(bool,__new__);
|
||||
BIND_METHOD(bool,__repr__);
|
||||
BIND_METHOD(bool,__format__);
|
||||
krk_finalizeClass(_bool);
|
||||
KRK_DOC(_bool, "Returns False if the argument is 'falsey', otherwise True.");
|
||||
|
||||
KrkClass * _NoneType = ADD_BASE_CLASS(vm.baseClasses->noneTypeClass, "NoneType", vm.baseClasses->objectClass);
|
||||
_NoneType->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_METHOD(NoneType, __init__);
|
||||
BIND_METHOD(NoneType, __str__);
|
||||
_NoneType->allocSize = 0;
|
||||
BIND_STATICMETHOD(NoneType, __new__);
|
||||
BIND_METHOD(NoneType, __repr__);
|
||||
BIND_METHOD(NoneType, __hash__);
|
||||
BIND_METHOD(NoneType, __eq__);
|
||||
krk_defineNative(&_NoneType->methods, "__repr__", FUNC_NAME(NoneType,__str__));
|
||||
krk_finalizeClass(_NoneType);
|
||||
|
||||
KrkClass * _NotImplementedType = ADD_BASE_CLASS(vm.baseClasses->notImplClass, "NotImplementedType", vm.baseClasses->objectClass);
|
||||
_NotImplementedType->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_METHOD(NotImplementedType, __init__);
|
||||
BIND_METHOD(NotImplementedType, __str__);
|
||||
_NotImplementedType->allocSize = 0;
|
||||
BIND_STATICMETHOD(NotImplementedType, __new__);
|
||||
BIND_METHOD(NotImplementedType, __repr__);
|
||||
BIND_METHOD(NotImplementedType, __hash__);
|
||||
BIND_METHOD(NotImplementedType, __eq__);
|
||||
krk_defineNative(&_NotImplementedType->methods, "__repr__", FUNC_NAME(NotImplementedType,__str__));
|
||||
krk_finalizeClass(_NotImplementedType);
|
||||
|
||||
krk_attachNamedValue(&vm.builtins->fields, "NotImplemented", NOTIMPL_VAL());
|
||||
|
@ -54,7 +54,7 @@ KRK_Method(range,__init__) {
|
||||
self->step = _step;
|
||||
}
|
||||
}
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(range,__repr__) {
|
||||
@ -79,6 +79,22 @@ KRK_Method(range,__iter__) {
|
||||
return OBJECT_VAL(output);
|
||||
}
|
||||
|
||||
KRK_Method(range,__contains__) {
|
||||
int i;
|
||||
if (!krk_parseArgs(".i", (const char*[]){"i"}, &i)) return NONE_VAL();
|
||||
if (self->step == 1) return BOOLEAN_VAL(i >= self->min && i < self->max);
|
||||
if (self->step == -1) return BOOLEAN_VAL(i <= self->min && i > self->max);
|
||||
if (self->step > 0) {
|
||||
if (i >= self->max || i < self->min) return BOOLEAN_VAL(0);
|
||||
if ((i - self->min) % self->step) return BOOLEAN_VAL(0);
|
||||
return BOOLEAN_VAL(1);
|
||||
} else {
|
||||
if (i <= self->max || i > self->min) return BOOLEAN_VAL(0);
|
||||
if ((i - self->min) % -self->step) return BOOLEAN_VAL(0);
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
}
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
#define CURRENT_CTYPE struct RangeIterator *
|
||||
|
||||
@ -90,7 +106,7 @@ KRK_Method(rangeiterator,__init__) {
|
||||
self->i = i;
|
||||
self->max = max;
|
||||
self->step = step;
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(rangeiterator,__call__) {
|
||||
@ -117,6 +133,7 @@ void _createAndBind_rangeClass(void) {
|
||||
"With three arguments, a @p step may also be included.");
|
||||
BIND_METHOD(range,__iter__);
|
||||
BIND_METHOD(range,__repr__);
|
||||
BIND_METHOD(range,__contains__);
|
||||
KRK_DOC(range, "@brief Iterable object that produces sequential numeric values.");
|
||||
krk_finalizeClass(range);
|
||||
|
||||
|
@ -58,18 +58,18 @@ KRK_Method(set,__init__) {
|
||||
if (argc == 2) {
|
||||
if (krk_unpackIterable(argv[1], self, _set_init_callback)) return NONE_VAL();
|
||||
}
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(set,__contains__) {
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
KrkValue _unused;
|
||||
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &_unused));
|
||||
KrkValue v;
|
||||
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &v));
|
||||
}
|
||||
|
||||
KRK_Method(set,__repr__) {
|
||||
METHOD_TAKES_NONE();
|
||||
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL("{...}");
|
||||
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL(S("{...}"));
|
||||
if (!self->entries.capacity) return OBJECT_VAL(S("set()"));
|
||||
((KrkObj*)self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
|
||||
struct StringBuilder sb = {0};
|
||||
@ -80,22 +80,19 @@ KRK_Method(set,__repr__) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
KrkTableEntry * entry = &self->entries.entries[i];
|
||||
if (IS_KWARGS(entry->key)) continue;
|
||||
if (c > 0) {
|
||||
pushStringBuilderStr(&sb, ", ", 2);
|
||||
}
|
||||
if (c) pushStringBuilderStr(&sb, ", ", 2);
|
||||
c++;
|
||||
|
||||
KrkClass * type = krk_getType(entry->key);
|
||||
krk_push(entry->key);
|
||||
KrkValue result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) {
|
||||
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
|
||||
}
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
|
||||
}
|
||||
|
||||
pushStringBuilder(&sb,'}');
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return finishStringBuilder(&sb);
|
||||
|
||||
_error:
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
krk_discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(set,__and__) {
|
||||
@ -198,11 +195,11 @@ KRK_Method(set,__eq__) {
|
||||
if (self->entries.count != them->entries.count)
|
||||
return BOOLEAN_VAL(0);
|
||||
|
||||
KrkValue _unused;
|
||||
KrkValue v;
|
||||
|
||||
for (unsigned int i = 0; i < self->entries.capacity; ++i) {
|
||||
if (IS_KWARGS(self->entries.entries[i].key)) continue;
|
||||
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
|
||||
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
|
||||
}
|
||||
|
||||
return BOOLEAN_VAL(1);
|
||||
@ -216,10 +213,10 @@ KRK_Method(set,__lt__) {
|
||||
struct Set * them = AS_set(argv[1]);
|
||||
if (self->entries.count == them->entries.count)
|
||||
return BOOLEAN_VAL(0);
|
||||
KrkValue _unused;
|
||||
KrkValue v;
|
||||
for (unsigned int i = 0; i < self->entries.capacity; ++i) {
|
||||
if (IS_KWARGS(self->entries.entries[i].key)) continue;
|
||||
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
|
||||
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
|
||||
}
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
@ -230,10 +227,10 @@ KRK_Method(set,__le__) {
|
||||
if (!IS_set(argv[1]))
|
||||
return NOTIMPL_VAL();
|
||||
struct Set * them = AS_set(argv[1]);
|
||||
KrkValue _unused;
|
||||
KrkValue v;
|
||||
for (unsigned int i = 0; i < self->entries.capacity; ++i) {
|
||||
if (IS_KWARGS(self->entries.entries[i].key)) continue;
|
||||
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
|
||||
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
|
||||
}
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
@ -246,10 +243,10 @@ KRK_Method(set,__gt__) {
|
||||
struct Set * them = AS_set(argv[1]);
|
||||
if (self->entries.count == them->entries.count)
|
||||
return BOOLEAN_VAL(0);
|
||||
KrkValue _unused;
|
||||
KrkValue v;
|
||||
for (unsigned int i = 0; i < them->entries.capacity; ++i) {
|
||||
if (IS_KWARGS(them->entries.entries[i].key)) continue;
|
||||
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
|
||||
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
|
||||
}
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
@ -259,10 +256,10 @@ KRK_Method(set,__ge__) {
|
||||
if (!IS_set(argv[1]))
|
||||
return NOTIMPL_VAL();
|
||||
struct Set * them = AS_set(argv[1]);
|
||||
KrkValue _unused;
|
||||
KrkValue v;
|
||||
for (unsigned int i = 0; i < them->entries.capacity; ++i) {
|
||||
if (IS_KWARGS(them->entries.entries[i].key)) continue;
|
||||
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
|
||||
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
|
||||
}
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
@ -294,6 +291,18 @@ KRK_Method(set,clear) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(set,update) {
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
if (argc > 1) {
|
||||
if (IS_set(argv[1])) {
|
||||
krk_tableAddAll(&AS_set(argv[1])->entries, &self->entries);
|
||||
} else {
|
||||
if (krk_unpackIterable(argv[1], self, _set_init_callback)) return NONE_VAL();
|
||||
}
|
||||
}
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
FUNC_SIG(setiterator,__init__);
|
||||
|
||||
KRK_Method(set,__iter__) {
|
||||
@ -312,7 +321,7 @@ KRK_Method(setiterator,__init__) {
|
||||
CHECK_ARG(1,set,void*,source);
|
||||
self->set = argv[1];
|
||||
self->i = 0;
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(setiterator,__call__) {
|
||||
@ -378,7 +387,7 @@ void _createAndBind_setClass(void) {
|
||||
KRK_DOC(BIND_METHOD(set,clear),
|
||||
"@brief Empty the set.\n\n"
|
||||
"Removes all elements from the set, in-place.");
|
||||
krk_defineNative(&set->methods, "__str__", FUNC_NAME(set,__repr__));
|
||||
BIND_METHOD(set,update);
|
||||
krk_attachNamedValue(&set->methods, "__hash__", NONE_VAL());
|
||||
krk_finalizeClass(set);
|
||||
|
||||
|
@ -112,42 +112,30 @@ KRK_Method(slice,__init__) {
|
||||
self->step = NONE_VAL();
|
||||
}
|
||||
}
|
||||
return argv[0];
|
||||
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(slice,__repr__) {
|
||||
METHOD_TAKES_NONE();
|
||||
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL("slice(...)");
|
||||
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL(S("slice(...)"));
|
||||
((KrkObj*)self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
|
||||
struct StringBuilder sb = {0};
|
||||
pushStringBuilderStr(&sb,"slice(",6);
|
||||
|
||||
KrkClass * type;
|
||||
KrkValue result;
|
||||
|
||||
/* start */
|
||||
type = krk_getType(self->start);
|
||||
krk_push(self->start);
|
||||
result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", self->start)) goto _error;
|
||||
pushStringBuilderStr(&sb,", ",2);
|
||||
|
||||
/* end */
|
||||
type = krk_getType(self->end);
|
||||
krk_push(self->end);
|
||||
result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", self->end)) goto _error;
|
||||
pushStringBuilderStr(&sb,", ",2);
|
||||
|
||||
/* step */
|
||||
type = krk_getType(self->step);
|
||||
krk_push(self->step);
|
||||
result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
|
||||
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", self->step)) goto _error;
|
||||
pushStringBuilder(&sb,')');
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return finishStringBuilder(&sb);
|
||||
|
||||
_error:
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
krk_discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(slice,start) {
|
||||
@ -165,9 +153,30 @@ KRK_Method(slice,step) {
|
||||
return self->step;
|
||||
}
|
||||
|
||||
#undef CURRENT_CTYPE
|
||||
#define CURRENT_CTYPE KrkInstance *
|
||||
#define IS_ellipsis(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(ellipsis)))
|
||||
#define AS_ellipsis(o) ((KrkInstance*)AS_INSTANCE(o))
|
||||
|
||||
KRK_StaticMethod(ellipsis,__new__) {
|
||||
KrkClass * _class = NULL;
|
||||
if (!krk_parseArgs("O!", (const char*[]){"cls"}, KRK_BASE_CLASS(type), &_class)) return NONE_VAL();
|
||||
if (!krk_isSubClass(_class, KRK_BASE_CLASS(ellipsis))) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "%S is not a subclass of %S", _class->name, KRK_BASE_CLASS(ellipsis)->name);
|
||||
}
|
||||
|
||||
KrkValue out;
|
||||
if (!krk_tableGet_fast(&vm.builtins->fields, S("Ellipsis"), &out)) return krk_runtimeError(vm.exceptions->typeError, "Ellipsis is missing");
|
||||
return out;
|
||||
}
|
||||
|
||||
KRK_Method(ellipsis,__repr__) {
|
||||
return OBJECT_VAL(S("Ellipsis"));
|
||||
}
|
||||
|
||||
_noexport
|
||||
void _createAndBind_sliceClass(void) {
|
||||
KrkClass * slice = ADD_BASE_CLASS(vm.baseClasses->sliceClass, "slice", vm.baseClasses->objectClass);
|
||||
KrkClass * slice = ADD_BASE_CLASS(KRK_BASE_CLASS(slice), "slice", KRK_BASE_CLASS(object));
|
||||
slice->allocSize = sizeof(struct KrkSlice);
|
||||
slice->_ongcscan = _slice_gcscan;
|
||||
slice->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
@ -176,7 +185,14 @@ void _createAndBind_sliceClass(void) {
|
||||
BIND_PROP(slice,start);
|
||||
BIND_PROP(slice,end);
|
||||
BIND_PROP(slice,step);
|
||||
krk_defineNative(&slice->methods, "__str__", FUNC_NAME(slice,__repr__));
|
||||
krk_attachNamedValue(&slice->methods, "__hash__", NONE_VAL());
|
||||
krk_finalizeClass(slice);
|
||||
|
||||
KrkClass * ellipsis = ADD_BASE_CLASS(KRK_BASE_CLASS(ellipsis), "ellipsis", KRK_BASE_CLASS(object));
|
||||
krk_attachNamedObject(&vm.builtins->fields, "Ellipsis", (KrkObj*)krk_newInstance(ellipsis));
|
||||
ellipsis->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_STATICMETHOD(ellipsis,__new__);
|
||||
BIND_METHOD(ellipsis,__repr__);
|
||||
krk_finalizeClass(ellipsis);
|
||||
|
||||
}
|
||||
|
119
src/obj_str.c
119
src/obj_str.c
@ -27,12 +27,12 @@ KRK_Method(str,__ord__) {
|
||||
return INTEGER_VAL(krk_unicodeCodepoint(self,0));
|
||||
}
|
||||
|
||||
KRK_Method(str,__init__) {
|
||||
KRK_StaticMethod(str,__new__) {
|
||||
/* Ignore argument which would have been an instance */
|
||||
if (argc < 2) {
|
||||
return OBJECT_VAL(S(""));
|
||||
}
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
FUNCTION_TAKES_AT_MOST(2);
|
||||
if (IS_STRING(argv[1])) return argv[1]; /* strings are immutable, so we can just return the arg */
|
||||
/* Find the type of arg */
|
||||
krk_push(argv[1]);
|
||||
@ -56,7 +56,7 @@ KRK_Method(str,__add__) {
|
||||
bl = them->length;
|
||||
|
||||
size_t length = al + bl;
|
||||
char * chars = ALLOCATE(char, length + 1);
|
||||
char * chars = KRK_ALLOCATE(char, length + 1);
|
||||
memcpy(chars, a, al);
|
||||
memcpy(chars + al, b, bl);
|
||||
chars[length] = '\0';
|
||||
@ -101,7 +101,11 @@ KRK_Method(str,__int__) {
|
||||
/* str.__float__() */
|
||||
KRK_Method(str,__float__) {
|
||||
METHOD_TAKES_NONE();
|
||||
return FLOATING_VAL(strtod(AS_CSTRING(argv[0]),NULL));
|
||||
#ifndef KRK_NO_FLOAT
|
||||
return krk_parse_float(AS_CSTRING(argv[0]),AS_STRING(argv[0])->length);
|
||||
#else
|
||||
return krk_runtimeError(vm.exceptions->valueError, "no float support");
|
||||
#endif
|
||||
}
|
||||
|
||||
KRK_Method(str,__getitem__) {
|
||||
@ -586,8 +590,10 @@ KRK_Method(str,__mod__) {
|
||||
|
||||
if (IS_INTEGER(arg)) {
|
||||
krk_push(INTEGER_VAL(AS_INTEGER(arg)));
|
||||
#ifndef KRK_NO_FLOAT
|
||||
} else if (IS_FLOATING(arg)) {
|
||||
krk_push(INTEGER_VAL(AS_FLOATING(arg)));
|
||||
#endif
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->typeError, "%%i format: a number is required, not '%T'", arg);
|
||||
goto _exception;
|
||||
@ -819,17 +825,47 @@ KRK_Method(str,index) {
|
||||
}
|
||||
|
||||
KRK_Method(str,startswith) {
|
||||
METHOD_TAKES_EXACTLY(1); /* I know the Python versions of these take optional start, end... */
|
||||
CHECK_ARG(1,str,KrkString*,prefix);
|
||||
return BOOLEAN_VAL(substringMatch(self->chars,self->length,prefix->chars,prefix->length));
|
||||
KrkString * substr;
|
||||
int start = 0;
|
||||
int end = self->codesLength;
|
||||
if (!krk_parseArgs(".O!|ii",(const char*[]){"prefix","start","end"}, KRK_BASE_CLASS(str), &substr, &start, &end)) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
WRAP_INDEX(start);
|
||||
WRAP_INDEX(end);
|
||||
|
||||
krk_unicodeString(self);
|
||||
krk_unicodeString(substr);
|
||||
|
||||
if (end < start || (size_t)(end - start) < substr->codesLength) return BOOLEAN_VAL(0);
|
||||
|
||||
for (size_t i = 0; i < substr->codesLength; ++i) {
|
||||
if (KRK_STRING_FAST(self, start + i) != KRK_STRING_FAST(substr,i)) return BOOLEAN_VAL(0);
|
||||
}
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
|
||||
KRK_Method(str,endswith) {
|
||||
METHOD_TAKES_EXACTLY(1); /* I know the Python versions of these take optional start, end... */
|
||||
CHECK_ARG(1,str,KrkString*,suffix);
|
||||
if (suffix->length > self->length) return BOOLEAN_VAL(0);
|
||||
return BOOLEAN_VAL(substringMatch(self->chars + (self->length - suffix->length),
|
||||
suffix->length, suffix->chars, suffix->length));
|
||||
KrkString * substr;
|
||||
int start = 0;
|
||||
int end = self->codesLength;
|
||||
if (!krk_parseArgs(".O!|ii",(const char*[]){"suffix","start","end"}, KRK_BASE_CLASS(str), &substr, &start, &end)) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
WRAP_INDEX(start);
|
||||
WRAP_INDEX(end);
|
||||
|
||||
krk_unicodeString(self);
|
||||
krk_unicodeString(substr);
|
||||
|
||||
if (end < start || (size_t)(end - start) < substr->codesLength) return BOOLEAN_VAL(0);
|
||||
|
||||
for (size_t i = 0; i < substr->codesLength; ++i) {
|
||||
if (KRK_STRING_FAST(self, (end - i - 1)) != KRK_STRING_FAST(substr,(substr->codesLength - i - 1))) return BOOLEAN_VAL(0);
|
||||
}
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -856,33 +892,35 @@ KRK_Method(str,__repr__) {
|
||||
pushStringBuilder(&sb, quote);
|
||||
|
||||
for (char * c = AS_CSTRING(argv[0]); c < end; ++c) {
|
||||
switch (*c) {
|
||||
unsigned char ch = *c;
|
||||
int addSlash = 0;
|
||||
switch (ch) {
|
||||
/* XXX: Other non-printables should probably be escaped as well. */
|
||||
case '\\': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'\\'); break;
|
||||
case '\'': if (quote == *c) { pushStringBuilder(&sb,'\\'); } pushStringBuilder(&sb,'\''); break;
|
||||
case '\"': if (quote == *c) { pushStringBuilder(&sb,'\\'); } pushStringBuilder(&sb,'\"'); break;
|
||||
case '\a': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'a'); break;
|
||||
case '\b': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'b'); break;
|
||||
case '\f': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'f'); break;
|
||||
case '\n': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'n'); break;
|
||||
case '\r': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'r'); break;
|
||||
case '\t': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'t'); break;
|
||||
case '\v': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'v'); break;
|
||||
case 27: pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'['); break;
|
||||
default: {
|
||||
if ((unsigned char)*c < ' ' || (unsigned char)*c == 0x7F) {
|
||||
case '\'': addSlash = (quote == ch); ch = '\''; break;
|
||||
case '\"': addSlash = (quote == ch); ch = '\"'; break;
|
||||
case '\\': addSlash = 1; ch = '\\'; break;
|
||||
case '\a': addSlash = 1; ch = 'a'; break;
|
||||
case '\b': addSlash = 1; ch = 'b'; break;
|
||||
case '\f': addSlash = 1; ch = 'f'; break;
|
||||
case '\n': addSlash = 1; ch = 'n'; break;
|
||||
case '\r': addSlash = 1; ch = 'r'; break;
|
||||
case '\t': addSlash = 1; ch = 't'; break;
|
||||
case '\v': addSlash = 1; ch = 'v'; break;
|
||||
case 27: addSlash = 1; ch = '['; break;
|
||||
default:
|
||||
if (ch < ' ' || ch == 0x7F) {
|
||||
pushStringBuilder(&sb,'\\');
|
||||
pushStringBuilder(&sb,'x');
|
||||
char hex[3];
|
||||
snprintf(hex, 3, "%02x", (unsigned char)*c);
|
||||
pushStringBuilder(&sb,hex[0]);
|
||||
pushStringBuilder(&sb,hex[1]);
|
||||
} else {
|
||||
pushStringBuilder(&sb,*c);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (addSlash) krk_pushStringBuilder(&sb,'\\');
|
||||
krk_pushStringBuilder(&sb,ch);
|
||||
}
|
||||
|
||||
pushStringBuilder(&sb, quote);
|
||||
@ -1012,7 +1050,8 @@ KRK_Method(striterator,__init__) {
|
||||
krk_push(OBJECT_VAL(self));
|
||||
krk_attachNamedObject(&self->fields, "s", (KrkObj*)base);
|
||||
krk_attachNamedValue(&self->fields, "i", INTEGER_VAL(0));
|
||||
return krk_pop();
|
||||
krk_pop();
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(striterator,__call__) {
|
||||
@ -1043,8 +1082,8 @@ _corrupt:
|
||||
void krk_pushStringBuilder(struct StringBuilder * sb, char c) {
|
||||
if (sb->capacity < sb->length + 1) {
|
||||
size_t old = sb->capacity;
|
||||
sb->capacity = GROW_CAPACITY(old);
|
||||
sb->bytes = GROW_ARRAY(char, sb->bytes, old, sb->capacity);
|
||||
sb->capacity = KRK_GROW_CAPACITY(old);
|
||||
sb->bytes = KRK_GROW_ARRAY(char, sb->bytes, old, sb->capacity);
|
||||
}
|
||||
sb->bytes[sb->length++] = c;
|
||||
}
|
||||
@ -1054,9 +1093,9 @@ void krk_pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t
|
||||
size_t prevcap = sb->capacity;
|
||||
while (sb->capacity < sb->length + len) {
|
||||
size_t old = sb->capacity;
|
||||
sb->capacity = GROW_CAPACITY(old);
|
||||
sb->capacity = KRK_GROW_CAPACITY(old);
|
||||
}
|
||||
sb->bytes = GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
|
||||
sb->bytes = KRK_GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
|
||||
}
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
sb->bytes[sb->length++] = *(str++);
|
||||
@ -1064,7 +1103,7 @@ void krk_pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t
|
||||
}
|
||||
|
||||
static void _freeStringBuilder(struct StringBuilder * sb) {
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
KRK_FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
sb->bytes = NULL;
|
||||
sb->length = 0;
|
||||
sb->capacity = 0;
|
||||
@ -1094,9 +1133,7 @@ int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va
|
||||
}
|
||||
|
||||
/* Bail on exception */
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
|
||||
return 0;
|
||||
}
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) break;
|
||||
|
||||
++f;
|
||||
|
||||
@ -1188,6 +1225,8 @@ int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va
|
||||
krk_push(res);
|
||||
if (IS_STRING(res)) {
|
||||
pushStringBuilderStr(sb, AS_CSTRING(res), AS_STRING(res)->length);
|
||||
} else if (!(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "__repr__ returned non-string (type %T)", res);
|
||||
}
|
||||
krk_pop();
|
||||
}
|
||||
@ -1212,6 +1251,7 @@ int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va
|
||||
}
|
||||
}
|
||||
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1237,7 +1277,8 @@ _noexport
|
||||
void _createAndBind_strClass(void) {
|
||||
KrkClass * str = ADD_BASE_CLASS(vm.baseClasses->strClass, "str", vm.baseClasses->objectClass);
|
||||
str->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
BIND_METHOD(str,__init__);
|
||||
str->allocSize = 0;
|
||||
BIND_STATICMETHOD(str,__new__);
|
||||
BIND_METHOD(str,__iter__);
|
||||
BIND_METHOD(str,__ord__);
|
||||
BIND_METHOD(str,__int__);
|
||||
|
@ -13,8 +13,8 @@ static int _tuple_init_callback(void * context, const KrkValue * values, size_t
|
||||
KrkValueArray * positionals = context;
|
||||
if (positionals->count + count > positionals->capacity) {
|
||||
size_t old = positionals->capacity;
|
||||
positionals->capacity = (count == 1) ? GROW_CAPACITY(old) : (positionals->count + count);
|
||||
positionals->values = GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
|
||||
positionals->capacity = (count == 1) ? KRK_GROW_CAPACITY(old) : (positionals->count + count);
|
||||
positionals->values = KRK_GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
@ -24,21 +24,16 @@ static int _tuple_init_callback(void * context, const KrkValue * values, size_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
static KrkValue _tuple_init(int argc, const KrkValue argv[], int hasKw) {
|
||||
KRK_StaticMethod(tuple,__new__) {
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
if (argc == 1) {
|
||||
return OBJECT_VAL(krk_newTuple(0));
|
||||
} else if (argc == 2) {
|
||||
/* Expand argument as an iterable. */
|
||||
krk_push(OBJECT_VAL(krk_newTuple(0)));
|
||||
KrkValueArray * positionals = &AS_TUPLE(krk_peek(0))->values;
|
||||
KrkValue other = argv[1];
|
||||
krk_unpackIterable(other, positionals, _tuple_init_callback);
|
||||
return krk_pop();
|
||||
} else {
|
||||
return krk_runtimeError(vm.exceptions->argumentError,
|
||||
"%s() takes %s %d argument%s (%d given)",
|
||||
"tuple","at most",1,"",argc-1);
|
||||
}
|
||||
krk_push(OBJECT_VAL(krk_newTuple(0)));
|
||||
KrkValueArray * positionals = &AS_TUPLE(krk_peek(0))->values;
|
||||
KrkValue other = argv[1];
|
||||
krk_unpackIterable(other, positionals, _tuple_init_callback);
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
/* tuple creator */
|
||||
@ -153,15 +148,8 @@ KRK_Method(tuple,__repr__) {
|
||||
pushStringBuilder(&sb, '(');
|
||||
|
||||
for (size_t i = 0; i < self->values.count; ++i) {
|
||||
KrkClass * type = krk_getType(self->values.values[i]);
|
||||
krk_push(self->values.values[i]);
|
||||
KrkValue result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) {
|
||||
pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
|
||||
}
|
||||
if (i != self->values.count - 1) {
|
||||
pushStringBuilderStr(&sb, ", ", 2);
|
||||
}
|
||||
if (i) pushStringBuilderStr(&sb, ", ", 2);
|
||||
if (!krk_pushStringBuilderFormat(&sb, "%R", self->values.values[i])) goto _error;
|
||||
}
|
||||
|
||||
if (self->values.count == 1) {
|
||||
@ -171,6 +159,11 @@ KRK_Method(tuple,__repr__) {
|
||||
pushStringBuilder(&sb, ')');
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return finishStringBuilder(&sb);
|
||||
|
||||
_error:
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
krk_discardStringBuilder(&sb);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KRK_Method(tuple,__add__) {
|
||||
@ -273,6 +266,8 @@ _noexport
|
||||
void _createAndBind_tupleClass(void) {
|
||||
KrkClass * tuple = ADD_BASE_CLASS(vm.baseClasses->tupleClass, "tuple", vm.baseClasses->objectClass);
|
||||
tuple->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
|
||||
tuple->allocSize = 0;
|
||||
BIND_STATICMETHOD(tuple,__new__);
|
||||
BIND_METHOD(tuple,__repr__);
|
||||
BIND_METHOD(tuple,__getitem__);
|
||||
BIND_METHOD(tuple,__len__);
|
||||
@ -286,8 +281,6 @@ void _createAndBind_tupleClass(void) {
|
||||
BIND_METHOD(tuple,__hash__);
|
||||
BIND_METHOD(tuple,__add__);
|
||||
BIND_METHOD(tuple,__mul__);
|
||||
krk_defineNative(&tuple->methods, "__init__", _tuple_init);
|
||||
krk_defineNative(&tuple->methods, "__str__", FUNC_NAME(tuple,__repr__));
|
||||
krk_finalizeClass(tuple);
|
||||
|
||||
ADD_BASE_CLASS(vm.baseClasses->tupleiteratorClass, "tupleiterator", vm.baseClasses->objectClass);
|
||||
|
20
src/object.c
20
src/object.c
@ -7,6 +7,7 @@
|
||||
#include <kuroko/value.h>
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/table.h>
|
||||
#include <kuroko/threads.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
@ -171,6 +172,8 @@ uint32_t krk_unicodeCodepoint(KrkString * string, size_t index) {
|
||||
}
|
||||
}
|
||||
|
||||
extern int krk_tableSetExact(KrkTable * table, KrkValue key, KrkValue value);
|
||||
|
||||
static KrkString * allocateString(char * chars, size_t length, uint32_t hash) {
|
||||
size_t codesLength = 0;
|
||||
int type = checkString(chars,length,&codesLength);
|
||||
@ -186,7 +189,7 @@ static KrkString * allocateString(char * chars, size_t length, uint32_t hash) {
|
||||
string->codes = NULL;
|
||||
if (type == KRK_OBJ_FLAGS_STRING_ASCII) string->codes = string->chars;
|
||||
krk_push(OBJECT_VAL(string));
|
||||
krk_tableSet(&vm.strings, OBJECT_VAL(string), NONE_VAL());
|
||||
krk_tableSetExact(&vm.strings, OBJECT_VAL(string), NONE_VAL());
|
||||
krk_pop();
|
||||
_release_lock(_stringLock);
|
||||
return string;
|
||||
@ -207,7 +210,7 @@ KrkString * krk_takeString(char * chars, size_t length) {
|
||||
_obtain_lock(_stringLock);
|
||||
KrkString * interned = krk_tableFindString(&vm.strings, chars, length, hash);
|
||||
if (interned != NULL) {
|
||||
free(chars); /* This string isn't owned by us yet, so free, not FREE_ARRAY */
|
||||
free(chars); /* This string isn't owned by us yet, so free, not KRK_FREE_ARRAY */
|
||||
_release_lock(_stringLock);
|
||||
return interned;
|
||||
}
|
||||
@ -226,7 +229,7 @@ KrkString * krk_copyString(const char * chars, size_t length) {
|
||||
_release_lock(_stringLock);
|
||||
return interned;
|
||||
}
|
||||
char * heapChars = ALLOCATE(char, length + 1);
|
||||
char * heapChars = KRK_ALLOCATE(char, length + 1);
|
||||
memcpy(heapChars, chars ? chars : "", length);
|
||||
heapChars[length] = '\0';
|
||||
KrkString * result = allocateString(heapChars, length, hash);
|
||||
@ -239,7 +242,7 @@ KrkString * krk_takeStringVetted(char * chars, size_t length, size_t codesLength
|
||||
_obtain_lock(_stringLock);
|
||||
KrkString * interned = krk_tableFindString(&vm.strings, chars, length, hash);
|
||||
if (interned != NULL) {
|
||||
FREE_ARRAY(char, chars, length + 1);
|
||||
KRK_FREE_ARRAY(char, chars, length + 1);
|
||||
_release_lock(_stringLock);
|
||||
return interned;
|
||||
}
|
||||
@ -252,7 +255,7 @@ KrkString * krk_takeStringVetted(char * chars, size_t length, size_t codesLength
|
||||
string->codes = NULL;
|
||||
if (type == KRK_OBJ_FLAGS_STRING_ASCII) string->codes = string->chars;
|
||||
krk_push(OBJECT_VAL(string));
|
||||
krk_tableSet(&vm.strings, OBJECT_VAL(string), NONE_VAL());
|
||||
krk_tableSetExact(&vm.strings, OBJECT_VAL(string), NONE_VAL());
|
||||
krk_pop();
|
||||
_release_lock(_stringLock);
|
||||
return string;
|
||||
@ -271,6 +274,7 @@ KrkCodeObject * krk_newCodeObject(void) {
|
||||
krk_initValueArray(&codeobject->positionalArgNames);
|
||||
krk_initValueArray(&codeobject->keywordArgNames);
|
||||
krk_initChunk(&codeobject->chunk);
|
||||
codeobject->jumpTargets = NONE_VAL();
|
||||
return codeobject;
|
||||
}
|
||||
|
||||
@ -284,7 +288,7 @@ KrkNative * krk_newNative(NativeFn function, const char * name, int type) {
|
||||
}
|
||||
|
||||
KrkClosure * krk_newClosure(KrkCodeObject * function, KrkValue globals) {
|
||||
KrkUpvalue ** upvalues = ALLOCATE(KrkUpvalue*, function->upvalueCount);
|
||||
KrkUpvalue ** upvalues = KRK_ALLOCATE(KrkUpvalue*, function->upvalueCount);
|
||||
for (size_t i = 0; i < function->upvalueCount; ++i) {
|
||||
upvalues[i] = NULL;
|
||||
}
|
||||
@ -355,7 +359,7 @@ KrkTuple * krk_newTuple(size_t length) {
|
||||
krk_initValueArray(&tuple->values);
|
||||
krk_push(OBJECT_VAL(tuple));
|
||||
tuple->values.capacity = length;
|
||||
tuple->values.values = GROW_ARRAY(KrkValue,NULL,0,length);
|
||||
tuple->values.values = KRK_GROW_ARRAY(KrkValue,NULL,0,length);
|
||||
krk_pop();
|
||||
return tuple;
|
||||
}
|
||||
@ -365,7 +369,7 @@ KrkBytes * krk_newBytes(size_t length, uint8_t * source) {
|
||||
bytes->length = length;
|
||||
bytes->bytes = NULL;
|
||||
krk_push(OBJECT_VAL(bytes));
|
||||
bytes->bytes = ALLOCATE(uint8_t, length);
|
||||
bytes->bytes = KRK_ALLOCATE(uint8_t, length);
|
||||
bytes->obj.hash = -1;
|
||||
if (source) {
|
||||
memcpy(bytes->bytes, source, length);
|
||||
|
@ -25,16 +25,20 @@ typedef enum {
|
||||
#define CONSTANT(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
|
||||
#define OPERAND(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
|
||||
#define JUMP(opc,sign) OPCODE(opc)
|
||||
#define COMPLICATED(opc,more) OPCODE(opc)
|
||||
#define CLOSURE_MORE
|
||||
#define EXPAND_ARGS_MORE
|
||||
#define FORMAT_VALUE_MORE
|
||||
#define LOCAL_MORE
|
||||
#define OVERLONG_JUMP_MORE
|
||||
#include "opcodes.h"
|
||||
#undef SIMPLE
|
||||
#undef OPERANDB
|
||||
#undef OPERAND
|
||||
#undef CONSTANT
|
||||
#undef JUMP
|
||||
#undef COMPLICATED
|
||||
#undef OVERLONG_JUMP_MORE
|
||||
#undef CLOSURE_MORE
|
||||
#undef LOCAL_MORE
|
||||
#undef EXPAND_ARGS_MORE
|
||||
|
@ -42,14 +42,14 @@ SIMPLE(OP_EQUAL)
|
||||
SIMPLE(OP_UNSET)
|
||||
JUMP(OP_LOOP_ITER,-)
|
||||
CONSTANT(OP_SET_PROPERTY, NOOP)
|
||||
SIMPLE(OP_FINALIZE)
|
||||
SIMPLE(OP_TRY_ELSE)
|
||||
OPERAND(OP_SET_LOCAL, LOCAL_MORE)
|
||||
SIMPLE(OP_INVOKE_DELETE)
|
||||
SIMPLE(OP_RAISE_FROM)
|
||||
SIMPLE(OP_SHIFTLEFT)
|
||||
JUMP(OP_POP_JUMP_IF_FALSE,+)
|
||||
SIMPLE(OP_ANNOTATE)
|
||||
SIMPLE(OP_FILTER_EXCEPT)
|
||||
JUMP(OP_FILTER_EXCEPT,+)
|
||||
SIMPLE(OP_BITAND)
|
||||
SIMPLE(OP_NONE)
|
||||
SIMPLE(OP_POP)
|
||||
@ -75,12 +75,12 @@ SIMPLE(OP_NOT)
|
||||
OPERAND(OP_CALL, NOOP)
|
||||
JUMP(OP_PUSH_WITH,+)
|
||||
SIMPLE(OP_GREATER_EQUAL)
|
||||
CONSTANT(OP_CLASS_PROPERTY, NOOP)
|
||||
CONSTANT(OP_SET_NAME, NOOP)
|
||||
SIMPLE(OP_INPLACE_ADD)
|
||||
CONSTANT(OP_GET_METHOD, NOOP)
|
||||
CONSTANT(OP_CLASS,NOOP)
|
||||
CONSTANT(OP_GET_NAME, NOOP)
|
||||
SIMPLE(OP_LESS_EQUAL)
|
||||
SIMPLE(OP_DOCSTRING)
|
||||
SIMPLE(OP_END_FINALLY)
|
||||
SIMPLE(OP_MATMUL)
|
||||
SIMPLE(OP_MODULO)
|
||||
OPERAND(OP_MAKE_DICT, NOOP)
|
||||
@ -105,11 +105,22 @@ SIMPLE(OP_INPLACE_POW)
|
||||
JUMP(OP_YIELD_FROM,+)
|
||||
OPERAND(OP_MAKE_LIST, NOOP)
|
||||
OPERAND(OP_GET_LOCAL, LOCAL_MORE)
|
||||
SIMPLE(OP_END_FINALLY)
|
||||
SIMPLE(OP_INPLACE_MULTIPLY)
|
||||
OPERAND(OP_EXPAND_ARGS,EXPAND_ARGS_MORE)
|
||||
SIMPLE(OP_INHERIT)
|
||||
JUMP(OP_CALL_ITER,+)
|
||||
JUMP(OP_JUMP_IF_TRUE_OR_POP,+)
|
||||
SIMPLE(OP_TRY_ELSE)
|
||||
OPERAND(OP_MISSING_KW, NOOP)
|
||||
|
||||
SIMPLE(OP_LIST_EXTEND_TOP)
|
||||
SIMPLE(OP_LIST_APPEND_TOP)
|
||||
SIMPLE(OP_DICT_UPDATE_TOP)
|
||||
SIMPLE(OP_DICT_SET_TOP)
|
||||
SIMPLE(OP_SET_UPDATE_TOP)
|
||||
SIMPLE(OP_SET_ADD_TOP)
|
||||
SIMPLE(OP_TUPLE_FROM_LIST)
|
||||
|
||||
OPERAND(OP_UNPACK_EX,NOOP)
|
||||
JUMP(OP_ENTER_EXCEPT,+)
|
||||
SIMPLE(OP_SWAP_POP)
|
||||
COMPLICATED(OP_OVERLONG_JUMP,OVERLONG_JUMP_MORE)
|
||||
SIMPLE(OP_PUSH_BUILD_CLASS)
|
||||
|
209
src/parseargs.c
209
src/parseargs.c
@ -1,29 +1,75 @@
|
||||
/**
|
||||
* @brief Function argument parser.
|
||||
*
|
||||
* Provides a simple interface for parsing arguments passed to native functions.
|
||||
*
|
||||
* This is similar to CPython's PyArg_ParseTupleAndKeywords, and many of the options
|
||||
* work the same way (though with some exceptions). With the utilities provided here,
|
||||
* C bindings can parse positional and keyword arguments, with automatic type checking
|
||||
* and conversion to C types.
|
||||
*/
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
/**
|
||||
* For use with @c ! formats, collects a @c KrkClass* and compares if the arg
|
||||
* is set. As a special case, the type may be @c NULL in which case failure is
|
||||
* guaranteed; this allows the standard library to reference potentially
|
||||
* uninitialized types (like fileio.File which may be uninitialized if the
|
||||
* module is not loaded, but may still need to be referenced as a potential
|
||||
* type in a function like @c print ).
|
||||
* @brief Format a TypeError exception for an argument.
|
||||
*
|
||||
* @param method_name Method name from parseVArgs, after possibly modification by `:`
|
||||
* @param expected Description of expected type; generally a type name, but maybe something like "str of length 1".
|
||||
* @param arg The value passed that failed the type check.
|
||||
* @param argName Name of the argument. If NULL or zero-length, argument name is not included in the description.
|
||||
*/
|
||||
static int matchType(const char * _method_name, KrkClass * type, KrkValue arg) {
|
||||
if (arg != KWARGS_VAL(0) && !krk_isInstanceOf(arg, type)) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%T'",
|
||||
_method_name, type ? type->name->chars : "unknown type", arg);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
_cold
|
||||
static void raise_TypeError(const char * method_name, const char * expected, KrkValue arg, const char * argName) {
|
||||
krk_runtimeError(vm.exceptions->typeError,
|
||||
"%s()%s%s expects %s, not '%T'",
|
||||
method_name, (argName && *argName) ? " argument " : "", (argName && *argName) ? argName : "",
|
||||
expected, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the method name to use for an error message.
|
||||
*
|
||||
* If the format string has a ':' it is taken as the start of an alternative method name
|
||||
* to include in error messages. This may be useful when calling the macro version of
|
||||
* @c krk_parseArgs in a @c __new__ or @c __init__ method.
|
||||
*
|
||||
* @param method_name Original method name passed to krk_parseArgs.
|
||||
* @param fmt Pointer to somewhere in the format string up to the colon.
|
||||
*/
|
||||
_cold
|
||||
static const char * methodName(const char * method_name, const char * fmt) {
|
||||
const char * maybeColon = strchr(fmt, ':');
|
||||
return maybeColon ? maybeColon + 1 : method_name;
|
||||
}
|
||||
|
||||
/* Just to avoid repeating ourselves... */
|
||||
#define _method_name (methodName(orig_method_name, fmt))
|
||||
|
||||
/**
|
||||
* @brief Extract arguments from kwargs dict, but keep references to them.
|
||||
*
|
||||
* Searches for @p argName in the @p kwargs dict. If found, extracts the value
|
||||
* into @p out and stores a reference to it in @p refList and then deletes
|
||||
* the original entry from @p kwargs.
|
||||
*
|
||||
* @param kwargs Original keyword args dictionary, which will be mutated.
|
||||
* @param argName Argument name to search for.
|
||||
* @param out Slot to place argument value in.
|
||||
* @param refList List to store references for garbage collection.
|
||||
* @returns Non-zero if the argument was not found.
|
||||
*/
|
||||
static int extractKwArg(KrkTable * kwargs, KrkString * argName, KrkValue * out, KrkValueArray * refList) {
|
||||
if (!krk_tableGet_fast(kwargs, argName, out)) return 1;
|
||||
krk_writeValueArray(refList, *out);
|
||||
krk_tableDeleteExact(kwargs, OBJECT_VAL(argName));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validate and parse arguments to a function similar to how managed
|
||||
* function arguments are handled.
|
||||
*
|
||||
* This attempts to emulate CPythons' PyArg_ParseTupleAndKeywords.
|
||||
*
|
||||
* This works like a fancy scanf. We accept the original argument specification
|
||||
* (argc,argv,hasKw), a format string, an array of argument names, and then var
|
||||
* args that are generally pointers to where to stick results.
|
||||
@ -37,7 +83,7 @@ static int matchType(const char * _method_name, KrkClass * type, KrkValue arg) {
|
||||
* @returns 1 on success, 0 on error.
|
||||
*/
|
||||
int krk_parseVArgs(
|
||||
const char * _method_name,
|
||||
const char * orig_method_name,
|
||||
int argc, const KrkValue argv[], int hasKw,
|
||||
const char * fmt, const char ** names, va_list args) {
|
||||
int iarg = 0; /**< Index into positional input arguments */
|
||||
@ -58,7 +104,8 @@ int krk_parseVArgs(
|
||||
}
|
||||
|
||||
/* Required args */
|
||||
for (; *fmt; fmt++) {
|
||||
while (*fmt) {
|
||||
if (*fmt == ':') break;
|
||||
if (*fmt == '|') {
|
||||
/**
|
||||
* @c | begins optional arguments - eg. default args. Every format option after
|
||||
@ -70,6 +117,7 @@ int krk_parseVArgs(
|
||||
return 1;
|
||||
}
|
||||
required = 0;
|
||||
fmt++;
|
||||
continue;
|
||||
}
|
||||
if (*fmt == '*') {
|
||||
@ -88,6 +136,7 @@ int krk_parseVArgs(
|
||||
*out_v = &argv[iarg];
|
||||
iarg = argc;
|
||||
required = 0;
|
||||
fmt++;
|
||||
continue;
|
||||
}
|
||||
if (*fmt == '$') {
|
||||
@ -103,6 +152,7 @@ int krk_parseVArgs(
|
||||
return 1;
|
||||
}
|
||||
if (iarg < argc) break;
|
||||
fmt++;
|
||||
continue;
|
||||
}
|
||||
if (*fmt == '~') {
|
||||
@ -114,34 +164,47 @@ int krk_parseVArgs(
|
||||
* as for a @c **kwargs argument in a Kuroko function signature.
|
||||
*/
|
||||
acceptextrakws = 1;
|
||||
fmt++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int wasPositional = 0;
|
||||
KrkValue arg = KWARGS_VAL(0);
|
||||
krk_push(OBJECT_VAL(krk_copyString(names[oarg],strlen(names[oarg]))));
|
||||
|
||||
if (iarg < argc) {
|
||||
/* Positional arguments are pretty straightforward. */
|
||||
arg = argv[iarg];
|
||||
iarg++;
|
||||
wasPositional = 1;
|
||||
} else if ((required && !hasKw) || (hasKw && !krk_tableGet_fast(AS_DICT(argv[argc]), AS_STRING(krk_peek(0)), &arg) && required)) {
|
||||
} else if ((required && !hasKw) || (hasKw && extractKwArg(AS_DICT(argv[argc]), krk_copyString(names[oarg],strlen(names[oarg])), &arg, AS_LIST(argv[argc+1])) && required)) {
|
||||
/* If keyword argument lookup failed and this is not an optional argument, raise an exception. */
|
||||
krk_runtimeError(vm.exceptions->typeError, "%s() missing required positional argument: '%S'",
|
||||
_method_name, AS_STRING(krk_peek(0)));
|
||||
krk_runtimeError(vm.exceptions->typeError, "%s() missing required positional argument: '%s'",
|
||||
_method_name, names[oarg]);
|
||||
goto _error;
|
||||
}
|
||||
|
||||
if (hasKw && krk_tableDelete(AS_DICT(argv[argc]), krk_peek(0)) && wasPositional) {
|
||||
/* We remove all arguments from kwargs. If we got this argument from a positional argument,
|
||||
* and it was found during deletion, we raise a multiple-defs exception. */
|
||||
krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'",
|
||||
_method_name, AS_STRING(krk_peek(0)));
|
||||
goto _error;
|
||||
char argtype = *fmt++;
|
||||
|
||||
if (*fmt == '?') {
|
||||
/* "is present", useful for things where relying on a default isn't useful but you
|
||||
* still want to have all the type checking and automatic parsing. */
|
||||
fmt++;
|
||||
int * out = va_arg(args, int*);
|
||||
*out = !krk_valuesSame(arg, KWARGS_VAL(0));
|
||||
}
|
||||
|
||||
switch (*fmt) {
|
||||
if (*fmt == '!') {
|
||||
/* "of type", thrown an exception if the argument was present but was not
|
||||
* an instance of a given class. Originally just for @c O and @c V but
|
||||
* now available anywhere, though likely not useful for other types.
|
||||
* Maybe if you want @c p to only be a bool this could be useful? */
|
||||
fmt++;
|
||||
KrkClass * type = va_arg(args, KrkClass*);
|
||||
if (!krk_valuesSame(arg, KWARGS_VAL(0)) && !krk_isInstanceOf(arg, type)) {
|
||||
raise_TypeError(_method_name, type ? type->name->chars : "unknown type", arg, names[oarg]);
|
||||
goto _error;
|
||||
}
|
||||
}
|
||||
|
||||
switch (argtype) {
|
||||
/**
|
||||
* @c O Collect an object (with @c ! - of a given type) and place it in
|
||||
* in the @c KrkObj** var arg. The object must be a heap object,
|
||||
@ -152,17 +215,12 @@ int krk_parseVArgs(
|
||||
* before @c None can be evaluated).
|
||||
*/
|
||||
case 'O': {
|
||||
if (fmt[1] == '!') {
|
||||
fmt++;
|
||||
KrkClass * type = va_arg(args, KrkClass*);
|
||||
if (!matchType(_method_name, type, arg)) goto _error;
|
||||
}
|
||||
KrkObj ** out = va_arg(args, KrkObj**);
|
||||
if (arg != KWARGS_VAL(0)) {
|
||||
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
|
||||
if (IS_NONE(arg)) {
|
||||
*out = NULL;
|
||||
} else if (!IS_OBJECT(arg)) {
|
||||
TYPE_ERROR(heap object,arg);
|
||||
raise_TypeError(_method_name, "heap object", arg, names[oarg]);
|
||||
goto _error;
|
||||
} else {
|
||||
*out = AS_OBJECT(arg);
|
||||
@ -181,13 +239,8 @@ int krk_parseVArgs(
|
||||
* error message is less informative in this case.
|
||||
*/
|
||||
case 'V': {
|
||||
if (fmt[1] == '!') {
|
||||
fmt++;
|
||||
KrkClass * type = va_arg(args, KrkClass*);
|
||||
if (!matchType(_method_name, type, arg)) goto _error;
|
||||
}
|
||||
KrkValue * out = va_arg(args, KrkValue*);
|
||||
if (arg != KWARGS_VAL(0)) {
|
||||
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
|
||||
*out = arg;
|
||||
}
|
||||
break;
|
||||
@ -203,19 +256,19 @@ int krk_parseVArgs(
|
||||
case 'z': {
|
||||
char ** out = va_arg(args, char **);
|
||||
size_t * size = NULL;
|
||||
if (fmt[1] == '#') {
|
||||
if (*fmt == '#') {
|
||||
fmt++;
|
||||
size = va_arg(args, size_t*);
|
||||
}
|
||||
if (arg != KWARGS_VAL(0)) {
|
||||
if (arg == NONE_VAL()) {
|
||||
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
|
||||
if (IS_NONE(arg)) {
|
||||
*out = NULL;
|
||||
if (size) *size = 0;
|
||||
} else if (IS_STRING(arg)) {
|
||||
*out = AS_CSTRING(arg);
|
||||
if (size) *size = AS_STRING(arg)->length;
|
||||
} else {
|
||||
TYPE_ERROR(str or None,arg);
|
||||
raise_TypeError(_method_name, "str or None", arg, names[oarg]);
|
||||
goto _error;
|
||||
}
|
||||
}
|
||||
@ -228,16 +281,16 @@ int krk_parseVArgs(
|
||||
case 's': {
|
||||
char ** out = va_arg(args, char **);
|
||||
size_t * size = NULL;
|
||||
if (fmt[1] == '#') {
|
||||
if (*fmt == '#') {
|
||||
fmt++;
|
||||
size = va_arg(args, size_t*);
|
||||
}
|
||||
if (arg != KWARGS_VAL(0)) {
|
||||
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
|
||||
if (IS_STRING(arg)) {
|
||||
*out = AS_CSTRING(arg);
|
||||
if (size) *size = AS_STRING(arg)->length;
|
||||
} else {
|
||||
TYPE_ERROR(str,arg);
|
||||
raise_TypeError(_method_name, "str", arg, names[oarg]);
|
||||
goto _error;
|
||||
}
|
||||
}
|
||||
@ -253,7 +306,7 @@ int krk_parseVArgs(
|
||||
* both for future compatibility and to make intent clear, but have no
|
||||
* functional difference at this point.
|
||||
*/
|
||||
#define NUMERIC(c,type) case c: { type * out = va_arg(args, type*); if (arg != KWARGS_VAL(0)) { if (!krk_long_to_int(arg, sizeof(type), out)) goto _error; } break; }
|
||||
#define NUMERIC(c,type) case c: { type * out = va_arg(args, type*); if (!krk_valuesSame(arg, KWARGS_VAL(0))) { if (!krk_long_to_int(arg, sizeof(type), out)) goto _error; } break; }
|
||||
NUMERIC('b',unsigned char)
|
||||
NUMERIC('h',short)
|
||||
NUMERIC('H',unsigned short)
|
||||
@ -272,9 +325,9 @@ int krk_parseVArgs(
|
||||
*/
|
||||
case 'C': {
|
||||
int * out = va_arg(args, int*);
|
||||
if (arg != KWARGS_VAL(0)) {
|
||||
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
|
||||
if (!IS_STRING(arg) || AS_STRING(arg)->codesLength != 1) {
|
||||
TYPE_ERROR(str of length 1,arg);
|
||||
raise_TypeError(_method_name, "str of length 1", arg, names[oarg]);
|
||||
goto _error;
|
||||
}
|
||||
*out = krk_unicodeCodepoint(AS_STRING(arg),0);
|
||||
@ -282,15 +335,22 @@ int krk_parseVArgs(
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef KRK_NO_FLOAT
|
||||
/**
|
||||
* @c f Accept a Kuroko float as C float.
|
||||
*/
|
||||
case 'f': {
|
||||
float * out = va_arg(args, float*);
|
||||
if (arg != KWARGS_VAL(0)) {
|
||||
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
|
||||
if (!IS_FLOATING(arg)) {
|
||||
TYPE_ERROR(float,arg);
|
||||
goto _error;
|
||||
KrkClass * type = krk_getType(arg);
|
||||
krk_push(arg);
|
||||
if (!krk_bindMethod(type, S("__float__"))) {
|
||||
krk_pop();
|
||||
raise_TypeError(_method_name, "float", arg, names[oarg]);
|
||||
goto _error;
|
||||
}
|
||||
arg = krk_callStack(0);
|
||||
}
|
||||
*out = AS_FLOATING(arg);
|
||||
}
|
||||
@ -302,15 +362,27 @@ int krk_parseVArgs(
|
||||
*/
|
||||
case 'd': {
|
||||
double * out = va_arg(args, double*);
|
||||
if (arg != KWARGS_VAL(0)) {
|
||||
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
|
||||
if (!IS_FLOATING(arg)) {
|
||||
TYPE_ERROR(float,arg);
|
||||
goto _error;
|
||||
KrkClass * type = krk_getType(arg);
|
||||
krk_push(arg);
|
||||
if (!krk_bindMethod(type, S("__float__"))) {
|
||||
krk_pop();
|
||||
raise_TypeError(_method_name, "float", arg, names[oarg]);
|
||||
goto _error;
|
||||
}
|
||||
arg = krk_callStack(0);
|
||||
}
|
||||
*out = AS_FLOATING(arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case 'f':
|
||||
case 'd':
|
||||
krk_runtimeError(vm.exceptions->typeError, "no float support");
|
||||
goto _error;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @c p Accept any value and examine its truthiness, returning an @c int.
|
||||
@ -320,7 +392,7 @@ int krk_parseVArgs(
|
||||
*/
|
||||
case 'p': {
|
||||
int * out = va_arg(args, int*);
|
||||
if (arg != KWARGS_VAL(0)) {
|
||||
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
|
||||
*out = !krk_isFalsey(arg);
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _error;
|
||||
}
|
||||
@ -328,12 +400,11 @@ int krk_parseVArgs(
|
||||
}
|
||||
|
||||
default: {
|
||||
krk_runtimeError(vm.exceptions->typeError, "unrecognized directive '%c' in format string", *fmt);
|
||||
krk_runtimeError(vm.exceptions->typeError, "unrecognized directive '%c' in format string", argtype);
|
||||
goto _error;
|
||||
}
|
||||
}
|
||||
|
||||
krk_pop();
|
||||
oarg++;
|
||||
}
|
||||
|
||||
@ -357,6 +428,15 @@ int krk_parseVArgs(
|
||||
for (size_t i = 0; i < AS_DICT(argv[argc])->capacity; ++i) {
|
||||
KrkTableEntry * entry = &AS_DICT(argv[argc])->entries[i];
|
||||
if (IS_STRING(entry->key)) {
|
||||
/* See if this was the name of an argument, which means it was already provided as a positional argument. */
|
||||
for (int j = 0; j < oarg; ++j) {
|
||||
if (*names[j] && strlen(names[j]) == AS_STRING(entry->key)->length && !strcmp(names[j], AS_CSTRING(entry->key))) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%s'",
|
||||
_method_name, names[j]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Otherwise just say it was unexpected. */
|
||||
krk_runtimeError(vm.exceptions->typeError, "%s() got an unexpected keyword argument '%S'",
|
||||
_method_name, AS_STRING(entry->key));
|
||||
return 0;
|
||||
@ -367,7 +447,6 @@ int krk_parseVArgs(
|
||||
return 1;
|
||||
|
||||
_error:
|
||||
krk_pop(); /* name of argument with error */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -375,12 +454,12 @@ _error:
|
||||
* @brief Variable argument version of @c krk_parseVArgs.
|
||||
*/
|
||||
int krk_parseArgs_impl(
|
||||
const char * _method_name,
|
||||
const char * method_name,
|
||||
int argc, const KrkValue argv[], int hasKw,
|
||||
const char * format, const char ** names, ...) {
|
||||
va_list args;
|
||||
va_start(args, names);
|
||||
int result = krk_parseVArgs(_method_name,argc,argv,hasKw,format,names,args);
|
||||
int result = krk_parseVArgs(method_name,argc,argv,hasKw,format,names,args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
@ -67,3 +67,28 @@ struct ParsedFormatSpec {
|
||||
* This is the "sdbm" hash. I've been using it in various places for many years,
|
||||
* and this specific version apparently traces to gawk. */
|
||||
#define krk_hash_advance(hash,c) do { hash = (int)(c) + (hash << 6) + (hash << 16) - hash; } while (0)
|
||||
|
||||
#ifndef KRK_DISABLE_DEBUG
|
||||
#include <kuroko/debug.h>
|
||||
struct BreakpointEntry {
|
||||
KrkCodeObject * inFunction;
|
||||
size_t offset;
|
||||
int flags;
|
||||
uint8_t originalOpcode;
|
||||
};
|
||||
|
||||
#define MAX_BREAKPOINTS 32
|
||||
struct DebuggerState {
|
||||
int breakpointsCount;
|
||||
KrkDebugCallback debuggerHook;
|
||||
|
||||
/* XXX This was previously thread-local; it probably should still be
|
||||
* specific to an individual thread... but we don't really do
|
||||
* much thread debugging, so... */
|
||||
int repeatStack_top;
|
||||
int repeatStack_bottom;
|
||||
int thisWasForced;
|
||||
|
||||
struct BreakpointEntry breakpoints[MAX_BREAKPOINTS];
|
||||
};
|
||||
#endif
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <kuroko/kuroko.h>
|
||||
#include <kuroko/scanner.h>
|
||||
|
||||
KrkScanner krk_initScanner(const char * src) {
|
||||
@ -179,6 +180,12 @@ static KrkToken number(KrkScanner * scanner, char c) {
|
||||
while (isDigit(peek(scanner))) advance(scanner);
|
||||
}
|
||||
|
||||
if (peek(scanner) == 'e' || peek(scanner) == 'E') {
|
||||
advance(scanner);
|
||||
if (peek(scanner) == '+' || peek(scanner) == '-') advance(scanner);
|
||||
while (isDigit(peek(scanner))) advance(scanner);
|
||||
}
|
||||
|
||||
return makeToken(scanner, TOKEN_NUMBER);
|
||||
}
|
||||
|
||||
@ -349,9 +356,9 @@ KrkToken krk_scanToken(KrkScanner * scanner) {
|
||||
case '[': return makeToken(scanner, TOKEN_LEFT_SQUARE);
|
||||
case ']': return makeToken(scanner, TOKEN_RIGHT_SQUARE);
|
||||
case ',': return makeToken(scanner, TOKEN_COMMA);
|
||||
case '.': return makeToken(scanner, TOKEN_DOT);
|
||||
case ';': return makeToken(scanner, TOKEN_SEMICOLON);
|
||||
case '~': return makeToken(scanner, TOKEN_TILDE);
|
||||
case '.': return makeToken(scanner, peek(scanner) == '.' ? (peekNext(scanner,1) == '.' ? (advance(scanner), advance(scanner), TOKEN_ELLIPSIS) : TOKEN_DOT) : TOKEN_DOT);
|
||||
|
||||
case ':': return makeToken(scanner, match(scanner, '=') ? TOKEN_WALRUS : TOKEN_COLON);
|
||||
case '!': return makeToken(scanner, match(scanner, '=') ? TOKEN_BANG_EQUAL : TOKEN_BANG);
|
||||
|
73
src/sys.c
73
src/sys.c
@ -4,14 +4,14 @@
|
||||
#include <kuroko/util.h>
|
||||
|
||||
#define KRK_VERSION_MAJOR 1
|
||||
#define KRK_VERSION_MINOR 3
|
||||
#define KRK_VERSION_PATCH 1
|
||||
#define KRK_VERSION_LEVEL 0xF
|
||||
#define KRK_VERSION_SERIAL 0x0
|
||||
#define KRK_VERSION_MINOR 5
|
||||
#define KRK_VERSION_PATCH 0
|
||||
#define KRK_VERSION_LEVEL 0xa
|
||||
#define KRK_VERSION_SERIAL 0x1
|
||||
|
||||
#define KRK_VERSION_EXTRA_BASE ""
|
||||
#define KRK_VERSION_EXTRA_BASE "a1"
|
||||
|
||||
#ifndef STATIC_ONLY
|
||||
#ifndef KRK_STATIC_ONLY
|
||||
#define KRK_VERSION_EXTRA KRK_VERSION_EXTRA_BASE
|
||||
#else
|
||||
#define KRK_VERSION_EXTRA KRK_VERSION_EXTRA_BASE "-static"
|
||||
@ -23,6 +23,10 @@
|
||||
# define KRK_BUILD_COMPILER "GCC " __VERSION__
|
||||
#elif (defined(__clang__))
|
||||
# define KRK_BUILD_COMPILER "clang " __clang_version__
|
||||
#elif (defined(_MSC_VER) && !defined(__clang__))
|
||||
# define KRK_ARG_STR(str) #str
|
||||
# define KRK_ARG_LOL(s) KRK_ARG_STR(s)
|
||||
# define KRK_BUILD_COMPILER "msvc " KRK_ARG_LOL(_MSC_FULL_VER)
|
||||
#else
|
||||
# define KRK_BUILD_COMPILER ""
|
||||
#endif
|
||||
@ -73,12 +77,15 @@ KRK_Function(getsizeof) {
|
||||
mySize += sizeof(uint8_t) * self->chunk.capacity;
|
||||
mySize += sizeof(KrkLineMap) * self->chunk.linesCapacity;
|
||||
mySize += sizeof(KrkValue) * self->chunk.constants.capacity;
|
||||
mySize += sizeof(KrkExpressionsMap) * self->expressionsCapacity;
|
||||
/* requiredArgNames */
|
||||
mySize += sizeof(KrkValue) * self->positionalArgNames.capacity;
|
||||
/* keywordArgNames */
|
||||
mySize += sizeof(KrkValue) * self->keywordArgNames.capacity;
|
||||
/* Locals array */
|
||||
mySize += sizeof(KrkLocalEntry) * self->localNameCount;
|
||||
/* Overlong jumps */
|
||||
mySize += sizeof(KrkOverlongJump) * self->overlongJumpsCapacity;
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_NATIVE: {
|
||||
@ -100,13 +107,13 @@ KRK_Function(getsizeof) {
|
||||
case KRK_OBJ_CLASS: {
|
||||
KrkClass * self = AS_CLASS(argv[0]);
|
||||
mySize += sizeof(KrkClass);
|
||||
mySize += sizeof(KrkTableEntry) * self->methods.capacity;
|
||||
mySize += sizeof(KrkTableEntry) * self->subclasses.capacity;
|
||||
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->methods.capacity;
|
||||
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->subclasses.capacity;
|
||||
break;
|
||||
}
|
||||
case KRK_OBJ_INSTANCE: {
|
||||
KrkInstance * self = AS_INSTANCE(argv[0]);
|
||||
mySize += sizeof(KrkTableEntry) * self->fields.capacity;
|
||||
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->fields.capacity;
|
||||
KrkClass * type = krk_getType(argv[0]);
|
||||
mySize += type->allocSize; /* All instance types have an allocSize set */
|
||||
|
||||
@ -114,7 +121,7 @@ KRK_Function(getsizeof) {
|
||||
if (krk_isInstanceOf(argv[0], vm.baseClasses->listClass)) {
|
||||
mySize += sizeof(KrkValue) * AS_LIST(argv[0])->capacity;
|
||||
} else if (krk_isInstanceOf(argv[0], vm.baseClasses->dictClass)) {
|
||||
mySize += sizeof(KrkTableEntry) * AS_DICT(argv[0])->capacity;
|
||||
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * AS_DICT(argv[0])->capacity;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -179,6 +186,44 @@ KRK_Function(inspect_value) {
|
||||
return OBJECT_VAL(krk_newBytes(sizeof(KrkValue),(uint8_t*)&argv[0]));
|
||||
}
|
||||
|
||||
KRK_Function(members) {
|
||||
KrkValue val;
|
||||
if (!krk_parseArgs("V", (const char*[]){"obj"}, &val)) return NONE_VAL();
|
||||
|
||||
KrkValue myDict = krk_dict_of(0,NULL,0);
|
||||
krk_push(myDict);
|
||||
|
||||
KrkTable * src = NULL;
|
||||
|
||||
if (IS_INSTANCE(val) || IS_CLASS(val)) {
|
||||
src = &AS_INSTANCE(val)->fields;
|
||||
} else if (IS_CLOSURE(val)) {
|
||||
src = &AS_CLOSURE(val)->fields;
|
||||
}
|
||||
|
||||
if (src) {
|
||||
krk_tableAddAll(src, AS_DICT(myDict));
|
||||
}
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
KRK_Function(set_recursion_depth) {
|
||||
unsigned int maxdepth;
|
||||
int quiet = 0;
|
||||
if (!krk_parseArgs("I|p",(const char*[]){"maxdepth","quiet"},&maxdepth,&quiet)) return NONE_VAL();
|
||||
if (krk_currentThread.exitOnFrame != 0) {
|
||||
if (quiet) return BOOLEAN_VAL(0);
|
||||
return krk_runtimeError(vm.exceptions->valueError, "Can not change recursion depth in this context.");
|
||||
}
|
||||
krk_setMaximumRecursionDepth(maxdepth);
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
|
||||
KRK_Function(get_recursion_depth) {
|
||||
return INTEGER_VAL(krk_currentThread.maximumCallDepth);
|
||||
}
|
||||
|
||||
void krk_module_init_kuroko(void) {
|
||||
/**
|
||||
* kuroko = module()
|
||||
@ -226,8 +271,14 @@ void krk_module_init_kuroko(void) {
|
||||
"Removes a module from the module table. It is not necessarily garbage collected if other references to it exist.");
|
||||
KRK_DOC(BIND_FUNC(vm.system,inspect_value),
|
||||
"Obtain the memory representation of a stack value.");
|
||||
KRK_DOC(BIND_FUNC(vm.system,members),
|
||||
"Obtain a copy of a dict of the direct members of an object.");
|
||||
KRK_DOC(BIND_FUNC(vm.system,set_recursion_depth),
|
||||
"Change the maximum recursion depth of the current thread if possible.");
|
||||
KRK_DOC(BIND_FUNC(vm.system,get_recursion_depth),
|
||||
"Examine the maximum recursion depth of the current thread.");
|
||||
krk_attachNamedObject(&vm.system->fields, "module", (KrkObj*)vm.baseClasses->moduleClass);
|
||||
krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(PATH_SEP));
|
||||
krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(KRK_PATH_SEP));
|
||||
KrkValue module_paths = krk_list_of(0,NULL,0);
|
||||
krk_attachNamedValue(&vm.system->fields, "module_paths", module_paths);
|
||||
krk_writeValueArray(AS_LIST(module_paths), OBJECT_VAL(S("./")));
|
||||
|
267
src/table.c
267
src/table.c
@ -1,4 +1,23 @@
|
||||
#include <stdio.h>
|
||||
/**
|
||||
* @file table.c
|
||||
* @brief Ordered hash map.
|
||||
*
|
||||
* The original table implementation was derived from CLox. CLox's
|
||||
* tables only supported string keys, but we support arbitrary values,
|
||||
* so long as they are hashable.
|
||||
*
|
||||
* This implementation maintains the same general API, but take its
|
||||
* inspiration from CPython to keep insertion order. The "entries"
|
||||
* table is still an array of key-value pairs, but no longer tracks
|
||||
* the hash lookup for the map. Instead, the entries array keeps
|
||||
* a strict insertion ordering, with deleted entries replaced with
|
||||
* sentinel values representing gaps. A separate "indexes" table
|
||||
* maps hash slots to their associated key-value pairs, or to -1
|
||||
* or -2 to represent unused and tombstone slots, respectively.
|
||||
*
|
||||
* When resizing a table, the entries array is rewritten and gaps
|
||||
* are removed. Simultaneously, the new index entries are populated.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <kuroko/kuroko.h>
|
||||
#include <kuroko/object.h>
|
||||
@ -9,16 +28,19 @@
|
||||
#include <kuroko/threads.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
#define TABLE_MAX_LOAD 0.75
|
||||
#define TABLE_MAX_LOAD 3 / 4
|
||||
|
||||
void krk_initTable(KrkTable * table) {
|
||||
table->count = 0;
|
||||
table->capacity = 0;
|
||||
table->used = 0;
|
||||
table->entries = NULL;
|
||||
table->indexes = NULL;
|
||||
}
|
||||
|
||||
void krk_freeTable(KrkTable * table) {
|
||||
FREE_ARRAY(KrkTableEntry, table->entries, table->capacity);
|
||||
KRK_FREE_ARRAY(KrkTableEntry, table->entries, table->capacity);
|
||||
KRK_FREE_ARRAY(ssize_t, table->indexes, table->capacity);
|
||||
krk_initTable(table);
|
||||
}
|
||||
|
||||
@ -38,8 +60,12 @@ inline int krk_hashValue(KrkValue value, uint32_t *hashOut) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
#ifndef KRK_NO_FLOAT
|
||||
*hashOut = (uint32_t)AS_FLOATING(value);
|
||||
return 0;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
KrkClass * type = krk_getType(value);
|
||||
if (type && type->_hash) {
|
||||
@ -50,7 +76,7 @@ inline int krk_hashValue(KrkValue value, uint32_t *hashOut) {
|
||||
return 0;
|
||||
}
|
||||
if (IS_CLASS(value)) {
|
||||
*hashOut = INTEGER_VAL((int)(intptr_t)AS_OBJECT(value));
|
||||
*hashOut = (uint32_t)((int)(intptr_t)AS_OBJECT(value));
|
||||
return 0;
|
||||
}
|
||||
_unhashable:
|
||||
@ -59,106 +85,117 @@ _unhashable:
|
||||
return 1;
|
||||
}
|
||||
|
||||
KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue key) {
|
||||
static inline ssize_t krk_tableIndexKeyC(const KrkTableEntry * entries, const ssize_t * indexes, size_t capacity, KrkValue key, int (*comparator)(KrkValue,KrkValue)) {
|
||||
uint32_t index;
|
||||
if (krk_hashValue(key, &index)) {
|
||||
return NULL;
|
||||
}
|
||||
index &= (capacity-1);
|
||||
KrkTableEntry * tombstone = NULL;
|
||||
if (krk_hashValue(key, &index)) return -1;
|
||||
index &= (capacity - 1);
|
||||
|
||||
ssize_t tombstone = -1;
|
||||
for (;;) {
|
||||
KrkTableEntry * entry = &entries[index];
|
||||
if (entry->key == KWARGS_VAL(0)) {
|
||||
return tombstone != NULL ? tombstone : entry;
|
||||
} else if (entry->key == KWARGS_VAL(1)) {
|
||||
if (tombstone == entry) return tombstone;
|
||||
if (tombstone == NULL) tombstone = entry;
|
||||
} else if (krk_valuesSameOrEqual(entry->key, key)) {
|
||||
return entry;
|
||||
if (indexes[index] == -1) {
|
||||
return tombstone != -1 ? tombstone : index;
|
||||
} else if (indexes[index] == -2) {
|
||||
if (tombstone == index) return tombstone;
|
||||
if (tombstone == -1) tombstone = index;
|
||||
} else if (comparator(entries[indexes[index]].key, key)) {
|
||||
return index;
|
||||
}
|
||||
index = (index + 1) & (capacity-1);
|
||||
index = (index + 1) & (capacity - 1);
|
||||
}
|
||||
}
|
||||
|
||||
KrkTableEntry * krk_findEntryExact(KrkTableEntry * entries, size_t capacity, KrkValue key) {
|
||||
uint32_t index;
|
||||
if (krk_hashValue(key, &index)) {
|
||||
return NULL;
|
||||
}
|
||||
index &= (capacity-1);
|
||||
KrkTableEntry * tombstone = NULL;
|
||||
for (;;) {
|
||||
KrkTableEntry * entry = &entries[index];
|
||||
if (entry->key == KWARGS_VAL(0)) {
|
||||
return tombstone != NULL ? tombstone : entry;
|
||||
} else if (entry->key == KWARGS_VAL(1)) {
|
||||
if (tombstone == entry) return tombstone;
|
||||
if (tombstone == NULL) tombstone = entry;
|
||||
} else if (krk_valuesSame(entry->key, key)) {
|
||||
return entry;
|
||||
}
|
||||
index = (index + 1) & (capacity-1);
|
||||
}
|
||||
static ssize_t krk_tableIndexKey(const KrkTableEntry * entries, const ssize_t * indexes, size_t capacity, KrkValue key) {
|
||||
return krk_tableIndexKeyC(entries,indexes,capacity,key,krk_valuesSameOrEqual);
|
||||
}
|
||||
|
||||
#ifdef __TINYC__
|
||||
int __builtin_clz(unsigned int x) {
|
||||
int i = 31;
|
||||
while (!(x & (1 << i)) && i >= 0) i--;
|
||||
return 31-i;
|
||||
static ssize_t krk_tableIndexKeyExact(const KrkTableEntry * entries, const ssize_t * indexes, size_t capacity, KrkValue key) {
|
||||
return krk_tableIndexKeyC(entries,indexes,capacity,key,krk_valuesSame);
|
||||
}
|
||||
#endif
|
||||
|
||||
void krk_tableAdjustCapacity(KrkTable * table, size_t capacity) {
|
||||
if (capacity) {
|
||||
/* Fast power-of-two calculation */
|
||||
size_t powerOfTwoCapacity = __builtin_clz(1) - __builtin_clz(capacity);
|
||||
if ((1UL << powerOfTwoCapacity) != capacity) powerOfTwoCapacity++;
|
||||
capacity = (1UL << powerOfTwoCapacity);
|
||||
}
|
||||
|
||||
KrkTableEntry * entries = ALLOCATE(KrkTableEntry, capacity);
|
||||
KrkTableEntry * nentries = KRK_ALLOCATE(KrkTableEntry, capacity);
|
||||
ssize_t * nindexes = KRK_ALLOCATE(ssize_t, capacity);
|
||||
for (size_t i = 0; i < capacity; ++i) {
|
||||
entries[i].key = KWARGS_VAL(0);
|
||||
entries[i].value = KWARGS_VAL(0);
|
||||
nindexes[i] = -1;
|
||||
nentries[i].key = KWARGS_VAL(0);
|
||||
nentries[i].value = KWARGS_VAL(0);
|
||||
}
|
||||
|
||||
table->count = 0;
|
||||
for (size_t i = 0; i < table->capacity; ++i) {
|
||||
KrkTableEntry * entry = &table->entries[i];
|
||||
if (IS_KWARGS(entry->key)) continue;
|
||||
KrkTableEntry * dest = krk_findEntry(entries, capacity, entry->key);
|
||||
dest->key = entry->key;
|
||||
dest->value = entry->value;
|
||||
table->count++;
|
||||
/* Fill in used entries */
|
||||
const KrkTableEntry * e = table->entries;
|
||||
for (size_t i = 0; i < table->count; ++i) {
|
||||
while (IS_KWARGS(e->key)) e++;
|
||||
memcpy(&nentries[i], e, sizeof(KrkTableEntry));
|
||||
ssize_t indexkey = krk_tableIndexKeyExact(nentries,nindexes,capacity, e->key);
|
||||
nindexes[indexkey] = i;
|
||||
e++;
|
||||
}
|
||||
|
||||
FREE_ARRAY(KrkTableEntry, table->entries, table->capacity);
|
||||
table->entries = entries;
|
||||
/* Swap before freeing */
|
||||
KrkTableEntry * oldEntries = table->entries;
|
||||
table->entries = nentries;
|
||||
KRK_FREE_ARRAY(KrkTableEntry, oldEntries, table->capacity);
|
||||
|
||||
ssize_t * oldIndexes = table->indexes;
|
||||
table->indexes = nindexes;
|
||||
KRK_FREE_ARRAY(ssize_t, oldIndexes, table->capacity);
|
||||
|
||||
/* Update table with new capacity and used count */
|
||||
table->capacity = capacity;
|
||||
table->used = table->count;
|
||||
}
|
||||
|
||||
int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) {
|
||||
if (table->count + 1 > table->capacity * TABLE_MAX_LOAD) {
|
||||
size_t capacity = GROW_CAPACITY(table->capacity);
|
||||
if (table->used + 1 > table->capacity * TABLE_MAX_LOAD) {
|
||||
size_t capacity = KRK_GROW_CAPACITY(table->capacity);
|
||||
krk_tableAdjustCapacity(table, capacity);
|
||||
}
|
||||
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
|
||||
if (!entry) return 0;
|
||||
int isNewKey = IS_KWARGS(entry->key);
|
||||
if (isNewKey) table->count++;
|
||||
entry->key = key;
|
||||
|
||||
ssize_t index = krk_tableIndexKey(table->entries, table->indexes, table->capacity, key);
|
||||
if (index < 0) return 0;
|
||||
KrkTableEntry * entry;
|
||||
int isNew = table->indexes[index] < 0;
|
||||
if (isNew) {
|
||||
table->indexes[index] = table->used;
|
||||
entry = &table->entries[table->used];
|
||||
entry->key = key;
|
||||
table->used++;
|
||||
table->count++;
|
||||
} else {
|
||||
entry = &table->entries[table->indexes[index]];
|
||||
}
|
||||
entry->value = value;
|
||||
return isNewKey;
|
||||
return isNew;
|
||||
}
|
||||
|
||||
int krk_tableSetExact(KrkTable * table, KrkValue key, KrkValue value) {
|
||||
if (table->used + 1 > table->capacity * TABLE_MAX_LOAD) {
|
||||
size_t capacity = KRK_GROW_CAPACITY(table->capacity);
|
||||
krk_tableAdjustCapacity(table, capacity);
|
||||
}
|
||||
|
||||
ssize_t index = krk_tableIndexKeyExact(table->entries, table->indexes, table->capacity, key);
|
||||
if (index < 0) return 0;
|
||||
KrkTableEntry * entry;
|
||||
int isNew = table->indexes[index] < 0;
|
||||
if (isNew) {
|
||||
table->indexes[index] = table->used;
|
||||
entry = &table->entries[table->used];
|
||||
entry->key = key;
|
||||
table->used++;
|
||||
table->count++;
|
||||
} else {
|
||||
entry = &table->entries[table->indexes[index]];
|
||||
}
|
||||
entry->value = value;
|
||||
return isNew;
|
||||
}
|
||||
|
||||
int krk_tableSetIfExists(KrkTable * table, KrkValue key, KrkValue value) {
|
||||
if (table->count == 0) return 0;
|
||||
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
|
||||
if (!entry) return 0;
|
||||
if (IS_KWARGS(entry->key)) return 0; /* Not found */
|
||||
entry->key = key;
|
||||
entry->value = value;
|
||||
ssize_t index = krk_tableIndexKey(table->entries, table->indexes, table->capacity, key);
|
||||
if (index < 0 || table->indexes[index] < 0) return 0;
|
||||
table->entries[table->indexes[index]].value = value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -173,75 +210,69 @@ void krk_tableAddAll(KrkTable * from, KrkTable * to) {
|
||||
|
||||
int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) {
|
||||
if (table->count == 0) return 0;
|
||||
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
|
||||
if (!entry || IS_KWARGS(entry->key)) {
|
||||
return 0;
|
||||
} else {
|
||||
*value = entry->value;
|
||||
return 1;
|
||||
}
|
||||
ssize_t index = krk_tableIndexKey(table->entries, table->indexes, table->capacity, key);
|
||||
if (index < 0 || table->indexes[index] < 0) return 0;
|
||||
*value = table->entries[table->indexes[index]].value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int krk_tableGet_fast(KrkTable * table, KrkString * str, KrkValue * value) {
|
||||
if (unlikely(table->count == 0)) return 0;
|
||||
if (table->count == 0) return 0;
|
||||
uint32_t index = str->obj.hash & (table->capacity-1);
|
||||
KrkTableEntry * tombstone = NULL;
|
||||
|
||||
ssize_t tombstone = -1;
|
||||
for (;;) {
|
||||
KrkTableEntry * entry = &table->entries[index];
|
||||
if (entry->key == KWARGS_VAL(0)) {
|
||||
if (table->indexes[index] == -1) {
|
||||
return 0;
|
||||
} else if (entry->key == KWARGS_VAL(1)) {
|
||||
if (tombstone == entry) return 0;
|
||||
if (tombstone == NULL) tombstone = entry;
|
||||
} else if (entry->key == OBJECT_VAL(str)) {
|
||||
*value = entry->value;
|
||||
} else if (table->indexes[index] == -2) {
|
||||
if (tombstone == index) return 0;
|
||||
if (tombstone == -1) tombstone = index;
|
||||
} else if (krk_valuesSame(table->entries[table->indexes[index]].key, OBJECT_VAL(str))) {
|
||||
*value = table->entries[table->indexes[index]].value;
|
||||
return 1;
|
||||
}
|
||||
index = (index + 1) & (table->capacity-1);
|
||||
index = (index + 1) & (table->capacity - 1);
|
||||
}
|
||||
}
|
||||
|
||||
int krk_tableDelete(KrkTable * table, KrkValue key) {
|
||||
if (table->count == 0) return 0;
|
||||
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
|
||||
if (!entry || IS_KWARGS(entry->key)) {
|
||||
return 0;
|
||||
}
|
||||
ssize_t index = krk_tableIndexKey(table->entries, table->indexes, table->capacity, key);
|
||||
if (index < 0 || table->indexes[index] < 0) return 0;
|
||||
table->count--;
|
||||
entry->key = KWARGS_VAL(1);
|
||||
entry->value = KWARGS_VAL(0);
|
||||
table->entries[table->indexes[index]].key = KWARGS_VAL(0);
|
||||
table->entries[table->indexes[index]].value = KWARGS_VAL(0);
|
||||
table->indexes[index] = -2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int krk_tableDeleteExact(KrkTable * table, KrkValue key) {
|
||||
if (table->count == 0) return 0;
|
||||
KrkTableEntry * entry = krk_findEntryExact(table->entries, table->capacity, key);
|
||||
if (!entry || IS_KWARGS(entry->key)) {
|
||||
return 0;
|
||||
}
|
||||
ssize_t index = krk_tableIndexKeyExact(table->entries, table->indexes, table->capacity, key);
|
||||
if (index < 0 || table->indexes[index] < 0) return 0;
|
||||
table->count--;
|
||||
entry->key = KWARGS_VAL(1);
|
||||
entry->value = KWARGS_VAL(0);
|
||||
table->entries[table->indexes[index]].key = KWARGS_VAL(0);
|
||||
table->entries[table->indexes[index]].value = KWARGS_VAL(0);
|
||||
table->indexes[index] = -2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
KrkString * krk_tableFindString(KrkTable * table, const char * chars, size_t length, uint32_t hash) {
|
||||
if (table->count == 0) return NULL;
|
||||
uint32_t index = hash & (table->capacity - 1);
|
||||
|
||||
uint32_t index = hash & (table->capacity-1);
|
||||
KrkTableEntry * tombstone = NULL;
|
||||
ssize_t tombstone = -1;
|
||||
for (;;) {
|
||||
KrkTableEntry * entry = &table->entries[index];
|
||||
if (entry->key == KWARGS_VAL(0)) {
|
||||
if (table->indexes[index] == -1) {
|
||||
return NULL;
|
||||
} else if (entry->key == KWARGS_VAL(1)) {
|
||||
if (tombstone == entry) return NULL;
|
||||
if (tombstone == NULL) tombstone = entry;
|
||||
} else if (AS_STRING(entry->key)->length == length &&
|
||||
AS_OBJECT(entry->key)->hash == hash &&
|
||||
memcmp(AS_STRING(entry->key)->chars, chars, length) == 0) {
|
||||
return AS_STRING(entry->key);
|
||||
} else if (table->indexes[index] == -2) {
|
||||
if (tombstone == index) return NULL;
|
||||
if (tombstone == -1) tombstone = index;
|
||||
} else if (AS_STRING(table->entries[table->indexes[index]].key)->length == length &&
|
||||
AS_OBJECT(table->entries[table->indexes[index]].key)->hash == hash &&
|
||||
memcmp(AS_STRING(table->entries[table->indexes[index]].key)->chars, chars, length) == 0) {
|
||||
return AS_STRING(table->entries[table->indexes[index]].key);
|
||||
}
|
||||
index = (index + 1) & (table->capacity-1);
|
||||
index = (index + 1) & (table->capacity - 1);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#ifndef KRK_DISABLE_THREADS
|
||||
#include <kuroko/util.h>
|
||||
#include <kuroko/threads.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
@ -36,6 +37,7 @@ struct Thread {
|
||||
pid_t tid;
|
||||
unsigned int started:1;
|
||||
unsigned int alive:1;
|
||||
unsigned int maxrec;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -61,11 +63,13 @@ KRK_Function(current_thread) {
|
||||
|
||||
static volatile int _threadLock = 0;
|
||||
static void * _startthread(void * _threadObj) {
|
||||
struct Thread * self = _threadObj;
|
||||
#if defined(__APPLE__) && defined(__aarch64__)
|
||||
krk_forceThreadData();
|
||||
#endif
|
||||
memset(&krk_currentThread, 0, sizeof(KrkThreadState));
|
||||
krk_currentThread.frames = calloc(vm.maximumCallDepth,sizeof(KrkCallFrame));
|
||||
krk_currentThread.maximumCallDepth = self->maxrec;
|
||||
krk_currentThread.frames = calloc(krk_currentThread.maximumCallDepth,sizeof(KrkCallFrame));
|
||||
vm.globalFlags |= KRK_GLOBAL_THREADS;
|
||||
_obtain_lock(_threadLock);
|
||||
if (vm.threads->next) {
|
||||
@ -75,7 +79,6 @@ static void * _startthread(void * _threadObj) {
|
||||
_release_lock(_threadLock);
|
||||
|
||||
/* Get our run function */
|
||||
struct Thread * self = _threadObj;
|
||||
self->threadState = &krk_currentThread;
|
||||
self->tid = gettid();
|
||||
|
||||
@ -104,7 +107,7 @@ static void * _startthread(void * _threadObj) {
|
||||
}
|
||||
_release_lock(_threadLock);
|
||||
|
||||
FREE_ARRAY(size_t, krk_currentThread.stack, krk_currentThread.stackSize);
|
||||
KRK_FREE_ARRAY(size_t, krk_currentThread.stack, krk_currentThread.stackSize);
|
||||
free(krk_currentThread.frames);
|
||||
|
||||
return NULL;
|
||||
@ -126,13 +129,15 @@ KRK_Method(Thread,join) {
|
||||
}
|
||||
|
||||
KRK_Method(Thread,start) {
|
||||
METHOD_TAKES_NONE();
|
||||
unsigned int maxrec = krk_currentThread.maximumCallDepth;
|
||||
if (!krk_parseArgs(".|I", (const char*[]){"maxrec"}, &maxrec)) return NONE_VAL();
|
||||
|
||||
if (self->started)
|
||||
return krk_runtimeError(KRK_EXC(ThreadError), "Thread has already been started.");
|
||||
|
||||
self->started = 1;
|
||||
self->alive = 1;
|
||||
self->maxrec = maxrec;
|
||||
pthread_create(&self->nativeRef, NULL, _startthread, (void*)self);
|
||||
|
||||
return argv[0];
|
||||
@ -152,7 +157,7 @@ KRK_Method(Thread,is_alive) {
|
||||
KRK_Method(Lock,__init__) {
|
||||
METHOD_TAKES_NONE(); /* TODO lock options, like recursive or error-checked? */
|
||||
pthread_mutex_init(&self->mutex, NULL);
|
||||
return argv[0];
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
static inline void _pushLockStatus(struct Lock * self, struct StringBuilder * sb) {
|
||||
|
56
src/time.c
56
src/time.c
@ -1,56 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/value.h>
|
||||
#include <kuroko/object.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
KRK_Function(sleep) {
|
||||
FUNCTION_TAKES_EXACTLY(1);
|
||||
|
||||
if (!IS_INTEGER(argv[0]) && !IS_FLOATING(argv[0])) {
|
||||
return TYPE_ERROR(int or float,argv[0]);
|
||||
}
|
||||
|
||||
unsigned int usecs = (IS_INTEGER(argv[0]) ? AS_INTEGER(argv[0]) :
|
||||
(IS_FLOATING(argv[0]) ? AS_FLOATING(argv[0]) : 0)) *
|
||||
1000000;
|
||||
|
||||
usleep(usecs);
|
||||
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
|
||||
KRK_Function(time) {
|
||||
FUNCTION_TAKES_NONE();
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
|
||||
double out = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
|
||||
|
||||
return FLOATING_VAL(out);
|
||||
}
|
||||
|
||||
void krk_module_init_time(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
|
||||
krk_attachNamedObject(&vm.modules, "time", (KrkObj*)module);
|
||||
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("time"));
|
||||
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
|
||||
KRK_DOC(module, "@brief Provides timekeeping functions.");
|
||||
KRK_DOC(BIND_FUNC(module,sleep), "@brief Pause execution of the current thread.\n"
|
||||
"@arguments secs\n\n"
|
||||
"Uses the system @c usleep() function to sleep for @p secs seconds, which may be a @ref float or @ref int. "
|
||||
"The available precision is platform-dependent.");
|
||||
KRK_DOC(BIND_FUNC(module,time), "@brief Return the elapsed seconds since the system epoch.\n\n"
|
||||
"Returns a @ref float representation of the number of seconds since the platform's epoch date. "
|
||||
"On POSIX platforms, this is the number of seconds since 1 January 1970. "
|
||||
"The precision of the return value is platform-dependent.");
|
||||
}
|
||||
|
133
src/value.c
133
src/value.c
@ -17,8 +17,8 @@ void krk_initValueArray(KrkValueArray * array) {
|
||||
void krk_writeValueArray(KrkValueArray * array, KrkValue value) {
|
||||
if (array->capacity < array->count + 1) {
|
||||
int old = array->capacity;
|
||||
array->capacity = GROW_CAPACITY(old);
|
||||
array->values = GROW_ARRAY(KrkValue, array->values, old, array->capacity);
|
||||
array->capacity = KRK_GROW_CAPACITY(old);
|
||||
array->values = KRK_GROW_ARRAY(KrkValue, array->values, old, array->capacity);
|
||||
}
|
||||
|
||||
array->values[array->count] = value;
|
||||
@ -26,129 +26,10 @@ void krk_writeValueArray(KrkValueArray * array, KrkValue value) {
|
||||
}
|
||||
|
||||
void krk_freeValueArray(KrkValueArray * array) {
|
||||
FREE_ARRAY(KrkValue, array->values, array->capacity);
|
||||
KRK_FREE_ARRAY(KrkValue, array->values, array->capacity);
|
||||
krk_initValueArray(array);
|
||||
}
|
||||
|
||||
void krk_printValue(FILE * f, KrkValue printable) {
|
||||
KrkClass * type = krk_getType(printable);
|
||||
if (type->_tostr) {
|
||||
krk_push(printable);
|
||||
printable = krk_callDirect(type->_tostr, 1);
|
||||
if (!IS_STRING(printable)) return;
|
||||
fprintf(f, "%s", AS_CSTRING(printable));
|
||||
} else if (type->_reprer) {
|
||||
krk_push(printable);
|
||||
printable = krk_callDirect(type->_reprer, 1);
|
||||
if (!IS_STRING(printable)) return;
|
||||
fprintf(f, "%s", AS_CSTRING(printable));
|
||||
} else {
|
||||
fprintf(f, "%s", krk_typeName(printable));
|
||||
}
|
||||
}
|
||||
|
||||
#define STRING_DEBUG_TRUNCATE 50
|
||||
|
||||
void krk_printValueSafe(FILE * f, KrkValue printable) {
|
||||
if (!IS_OBJECT(printable)) {
|
||||
switch (KRK_VAL_TYPE(printable)) {
|
||||
case KRK_VAL_INTEGER: fprintf(f, PRIkrk_int, AS_INTEGER(printable)); break;
|
||||
case KRK_VAL_BOOLEAN: fprintf(f, "%s", AS_BOOLEAN(printable) ? "True" : "False"); break;
|
||||
case KRK_VAL_NONE: fprintf(f, "None"); break;
|
||||
case KRK_VAL_HANDLER:
|
||||
switch (AS_HANDLER_TYPE(printable)) {
|
||||
case OP_PUSH_TRY: fprintf(f, "{try->%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_PUSH_WITH: fprintf(f, "{with->%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_RAISE: fprintf(f, "{raise<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_FILTER_EXCEPT: fprintf(f, "{except<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_BEGIN_FINALLY: fprintf(f, "{finally<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_RETURN: fprintf(f, "{return<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_END_FINALLY: fprintf(f, "{end<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_EXIT_LOOP: fprintf(f, "{exit<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
}
|
||||
break;
|
||||
case KRK_VAL_KWARGS: {
|
||||
if (AS_INTEGER(printable) == KWARGS_SINGLE) {
|
||||
fprintf(f, "{unpack single}");
|
||||
} else if (AS_INTEGER(printable) == KWARGS_LIST) {
|
||||
fprintf(f, "{unpack list}");
|
||||
} else if (AS_INTEGER(printable) == KWARGS_DICT) {
|
||||
fprintf(f, "{unpack dict}");
|
||||
} else if (AS_INTEGER(printable) == KWARGS_NIL) {
|
||||
fprintf(f, "{unpack nil}");
|
||||
} else if (AS_INTEGER(printable) == KWARGS_UNSET) {
|
||||
fprintf(f, "{unset default}");
|
||||
} else {
|
||||
fprintf(f, "{sentinel=" PRIkrk_int "}",AS_INTEGER(printable));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (IS_FLOATING(printable)) fprintf(f, "%.16g", AS_FLOATING(printable));
|
||||
break;
|
||||
}
|
||||
} else if (IS_STRING(printable)) {
|
||||
fprintf(f, "'");
|
||||
/*
|
||||
* Print at most STRING_DEBUG_TRUNCATE characters, as bytes, escaping anything not ASCII.
|
||||
* See also str.__repr__ which does something similar with escape sequences, but this
|
||||
* is a dumber, safer, and slightly faster approach.
|
||||
*/
|
||||
for (size_t c = 0; c < AS_STRING(printable)->length && c < STRING_DEBUG_TRUNCATE; ++c) {
|
||||
unsigned char byte = (unsigned char)AS_CSTRING(printable)[c];
|
||||
switch (byte) {
|
||||
case '\\': fprintf(f, "\\\\"); break;
|
||||
case '\n': fprintf(f, "\\n"); break;
|
||||
case '\r': fprintf(f, "\\r"); break;
|
||||
case '\'': fprintf(f, "\\'"); break;
|
||||
default: {
|
||||
if (byte < ' ' || byte > '~') {
|
||||
fprintf(f, "\\x%02x", byte);
|
||||
} else {
|
||||
fprintf(f, "%c", byte);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AS_STRING(printable)->length > STRING_DEBUG_TRUNCATE) {
|
||||
fprintf(f,"...");
|
||||
}
|
||||
fprintf(f,"'");
|
||||
} else {
|
||||
switch (AS_OBJECT(printable)->type) {
|
||||
case KRK_OBJ_CODEOBJECT: fprintf(f, "<codeobject %s>", AS_codeobject(printable)->name ? AS_codeobject(printable)->name->chars : "?"); break;
|
||||
case KRK_OBJ_CLASS: fprintf(f, "<class %s>", AS_CLASS(printable)->name ? AS_CLASS(printable)->name->chars : "?"); break;
|
||||
case KRK_OBJ_INSTANCE: fprintf(f, "<instance of %s>", AS_INSTANCE(printable)->_class->name->chars); break;
|
||||
case KRK_OBJ_NATIVE: fprintf(f, "<nativefn %s>", ((KrkNative*)AS_OBJECT(printable))->name); break;
|
||||
case KRK_OBJ_CLOSURE: fprintf(f, "<function %s>", AS_CLOSURE(printable)->function->name->chars); break;
|
||||
case KRK_OBJ_BYTES: fprintf(f, "<bytes of len %ld>", (long)AS_BYTES(printable)->length); break;
|
||||
case KRK_OBJ_TUPLE: {
|
||||
fprintf(f, "(");
|
||||
for (size_t i = 0; i < AS_TUPLE(printable)->values.count; ++i) {
|
||||
krk_printValueSafe(f, AS_TUPLE(printable)->values.values[i]);
|
||||
if (i + 1 != AS_TUPLE(printable)->values.count) {
|
||||
fprintf(f, ",");
|
||||
}
|
||||
}
|
||||
fprintf(f, ")");
|
||||
} break;
|
||||
case KRK_OBJ_BOUND_METHOD: fprintf(f, "<method %s>",
|
||||
AS_BOUND_METHOD(printable)->method ? (
|
||||
AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_CLOSURE ? ((KrkClosure*)AS_BOUND_METHOD(printable)->method)->function->name->chars :
|
||||
(AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_NATIVE ? ((KrkNative*)AS_BOUND_METHOD(printable)->method)->name : "(unknown)")) : "(corrupt bound method)"); break;
|
||||
default: fprintf(f, "<%s>", krk_typeName(printable)); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identity really should be the simple...
|
||||
*/
|
||||
int krk_valuesSame(KrkValue a, KrkValue b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
static inline int _krk_method_equivalence(KrkValue a, KrkValue b) {
|
||||
KrkClass * type = krk_getType(a);
|
||||
if (likely(type && type->_eq)) {
|
||||
@ -181,7 +62,7 @@ static inline int _krk_same_type_equivalence(uint16_t valtype, KrkValue a, KrkVa
|
||||
case KRK_VAL_NOTIMPL:
|
||||
case KRK_VAL_KWARGS:
|
||||
case KRK_VAL_HANDLER:
|
||||
return a == b;
|
||||
return krk_valuesSame(a,b);
|
||||
case KRK_VAL_OBJECT:
|
||||
default:
|
||||
return _krk_method_equivalence(a,b);
|
||||
@ -211,9 +92,9 @@ static inline int _krk_diff_type_equivalence(uint16_t val_a, uint16_t val_b, Krk
|
||||
return _krk_method_equivalence(a,b);
|
||||
}
|
||||
|
||||
__attribute__((hot))
|
||||
_hot
|
||||
int krk_valuesSameOrEqual(KrkValue a, KrkValue b) {
|
||||
if (a == b) return 1;
|
||||
if (krk_valuesSame(a,b)) return 1;
|
||||
uint16_t val_a = KRK_VAL_TYPE(a);
|
||||
uint16_t val_b = KRK_VAL_TYPE(b);
|
||||
return (val_a == val_b)
|
||||
@ -221,7 +102,7 @@ int krk_valuesSameOrEqual(KrkValue a, KrkValue b) {
|
||||
: _krk_diff_type_equivalence(val_a, val_b, a, b);
|
||||
}
|
||||
|
||||
__attribute__((hot))
|
||||
_hot
|
||||
int krk_valuesEqual(KrkValue a, KrkValue b) {
|
||||
uint16_t val_a = KRK_VAL_TYPE(a);
|
||||
uint16_t val_b = KRK_VAL_TYPE(b);
|
||||
|
55
src/vendor/rline.c
vendored
55
src/vendor/rline.c
vendored
@ -363,19 +363,19 @@ static void recalculate_tabs(line_t * line) {
|
||||
*/
|
||||
static const char * COLOR_FG = "@9";
|
||||
static const char * COLOR_BG = "@9";
|
||||
static const char * COLOR_ALT_FG = "@5";
|
||||
static const char * COLOR_ALT_FG = "@9";
|
||||
static const char * COLOR_ALT_BG = "@9";
|
||||
static const char * COLOR_KEYWORD = "@4";
|
||||
static const char * COLOR_STRING = "@2";
|
||||
static const char * COLOR_COMMENT = "@5";
|
||||
static const char * COLOR_TYPE = "@3";
|
||||
static const char * COLOR_PRAGMA = "@1";
|
||||
static const char * COLOR_NUMERAL = "@1";
|
||||
static const char * COLOR_RED = "@1";
|
||||
static const char * COLOR_GREEN = "@2";
|
||||
static const char * COLOR_ESCAPE = "@2";
|
||||
static const char * COLOR_SEARCH_FG = "@0";
|
||||
static const char * COLOR_SEARCH_BG = "@3";
|
||||
static const char * COLOR_KEYWORD = "@9";
|
||||
static const char * COLOR_STRING = "@9";
|
||||
static const char * COLOR_COMMENT = "@9";
|
||||
static const char * COLOR_TYPE = "@9";
|
||||
static const char * COLOR_PRAGMA = "@9";
|
||||
static const char * COLOR_NUMERAL = "@9";
|
||||
static const char * COLOR_RED = "@9";
|
||||
static const char * COLOR_GREEN = "@9";
|
||||
static const char * COLOR_ESCAPE = "@9";
|
||||
static const char * COLOR_SEARCH_FG = "@9";
|
||||
static const char * COLOR_SEARCH_BG = "@9";
|
||||
static const char * COLOR_ERROR_FG = "@9";
|
||||
static const char * COLOR_ERROR_BG = "@9";
|
||||
static const char * COLOR_BOLD = "@9";
|
||||
@ -560,7 +560,7 @@ static char * syn_krk_types[] = {
|
||||
"self", "super", /* implicit in a class method */
|
||||
"len", "str", "int", "float", "dir", "repr", /* global functions from __builtins__ */
|
||||
"list","dict","range", /* builtin classes */
|
||||
"object","exception","isinstance","type","tuple","reversed",
|
||||
"object","isinstance","type","tuple","reversed",
|
||||
"print","set","any","all","bool","ord","chr","hex","oct","filter",
|
||||
"sorted","bytes","getattr","sum","min","max","id","hash","map","bin",
|
||||
"enumerate","zip","setattr","property","staticmethod","classmethod",
|
||||
@ -672,6 +672,11 @@ static int paint_krk_numeral(struct syntax_state * state) {
|
||||
paint(1, FLAG_NUMERAL);
|
||||
while (isdigit(charat())) paint(1, FLAG_NUMERAL);
|
||||
}
|
||||
if (charat() == 'e' || charat() == 'E') {
|
||||
paint(1, FLAG_NUMERAL);
|
||||
if (charat() == '-' || charat() == '+') paint(1, FLAG_NUMERAL);
|
||||
while (isdigit(charat())) paint(1, FLAG_NUMERAL);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -2011,29 +2016,27 @@ static int handle_escape(int * this_buf, int * timeout, int c) {
|
||||
#ifndef _WIN32
|
||||
static unsigned int _INTR, _EOF;
|
||||
static struct termios old;
|
||||
static void get_initial_termios(void) {
|
||||
static void set_unbuffered(void) {
|
||||
tcgetattr(STDOUT_FILENO, &old);
|
||||
_INTR = old.c_cc[VINTR];
|
||||
_EOF = old.c_cc[VEOF];
|
||||
}
|
||||
static void set_unbuffered(void) {
|
||||
struct termios new = old;
|
||||
new.c_lflag &= (~ICANON & ~ECHO & ~ISIG);
|
||||
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &new);
|
||||
tcsetattr(STDOUT_FILENO, TCSADRAIN, &new);
|
||||
if (wcwidth(0x3042) != 2) setlocale(LC_CTYPE, "");
|
||||
}
|
||||
|
||||
static void set_buffered(void) {
|
||||
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &old);
|
||||
tcsetattr(STDOUT_FILENO, TCSADRAIN, &old);
|
||||
}
|
||||
#else
|
||||
static unsigned int _INTR = 3;
|
||||
static unsigned int _EOF = 4;
|
||||
static void get_initial_termios(void) {
|
||||
}
|
||||
static void set_unbuffered(void) {
|
||||
/* Disables line input, echo, ^C processing, and a few others. */
|
||||
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_VIRTUAL_TERMINAL_INPUT);
|
||||
SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||
setlocale(LC_CTYPE, "C.UTF-8");
|
||||
}
|
||||
static void set_buffered(void) {
|
||||
/* These are the defaults */
|
||||
@ -2429,12 +2432,6 @@ static int read_line(void) {
|
||||
* Read a line of text with interactive editing.
|
||||
*/
|
||||
int rline(char * buffer, int buf_size) {
|
||||
#ifndef _WIN32
|
||||
setlocale(LC_ALL, "");
|
||||
#else
|
||||
setlocale(LC_ALL, "C.UTF-8");
|
||||
#endif
|
||||
get_initial_termios();
|
||||
set_unbuffered();
|
||||
get_size();
|
||||
|
||||
@ -2442,8 +2439,12 @@ int rline(char * buffer, int buf_size) {
|
||||
offset = 0;
|
||||
buf_size_max = buf_size;
|
||||
|
||||
char * noColor = getenv("NO_COLOR");
|
||||
char * theme = getenv("RLINE_THEME");
|
||||
if (theme && !strcmp(theme,"sunsmoke")) { /* TODO bring back theme tables */
|
||||
if ((noColor && *noColor) || (theme && !strcmp(theme,"none"))) {
|
||||
/* If NO_COLOR is set, or RLINE_THEME=none, set no theme.
|
||||
* The default colors are all @9. */
|
||||
} else if (theme && !strcmp(theme,"sunsmoke")) {
|
||||
rline_exp_load_colorscheme_sunsmoke();
|
||||
} else {
|
||||
rline_exp_load_colorscheme_default();
|
||||
|
@ -1,389 +1,389 @@
|
||||
Checking {'hcl': '#602927', 'iyr': '2019', 'hgt': '186cm', 'byr': '1939', 'pid': '552194973', 'eyr': '2027', 'ecl': 'hzl'}
|
||||
Checking {'hcl': '#866857', 'iyr': '2015', 'hgt': '164cm', 'pid': '657988073', 'byr': '1996', 'eyr': '2020', 'ecl': 'brn'}
|
||||
Checking {'eyr': '2022', 'hcl': '#fffffd', 'iyr': '2017', 'hgt': '62in', 'byr': '1951', 'pid': '#6ef4e1', 'ecl': 'brn', 'cid': '321'}
|
||||
Checking {'eyr': '2027', 'hcl': '#602927', 'hgt': '186cm', 'byr': '1939', 'iyr': '2019', 'pid': '552194973', 'ecl': 'hzl'}
|
||||
Checking {'pid': '657988073', 'eyr': '2020', 'byr': '1996', 'ecl': 'brn', 'hcl': '#866857', 'iyr': '2015', 'hgt': '164cm'}
|
||||
Checking {'hcl': '#fffffd', 'byr': '1951', 'cid': '321', 'iyr': '2017', 'eyr': '2022', 'ecl': 'brn', 'hgt': '62in', 'pid': '#6ef4e1'}
|
||||
bad pid
|
||||
Checking {'ecl': 'brn', 'hcl': '#fffffd', 'iyr': '2011', 'hgt': '150cm', 'byr': '1980', 'pid': '420023864', 'eyr': '2025', 'cid': '129'}
|
||||
Checking {'hcl': '#ceb3a1', 'iyr': '2016', 'hgt': '187cm', 'byr': '1925', 'pid': '223151011', 'eyr': '2029', 'ecl': 'amb'}
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2010', 'hgt': '190cm', 'pid': '135392110', 'byr': '1959', 'ecl': 'brn', 'eyr': '2022'}
|
||||
Checking {'ecl': 'grn', 'hcl': '#a97842', 'iyr': '2018', 'pid': '522856696', 'byr': '1961', 'eyr': '2024', 'cid': '225'}
|
||||
Checking {'eyr': '2025', 'iyr': '2011', 'byr': '1980', 'hcl': '#fffffd', 'cid': '129', 'pid': '420023864', 'hgt': '150cm', 'ecl': 'brn'}
|
||||
Checking {'eyr': '2029', 'hcl': '#ceb3a1', 'hgt': '187cm', 'byr': '1925', 'ecl': 'amb', 'pid': '223151011', 'iyr': '2016'}
|
||||
Checking {'hcl': '#cfa07d', 'ecl': 'brn', 'eyr': '2022', 'pid': '135392110', 'iyr': '2010', 'hgt': '190cm', 'byr': '1959'}
|
||||
Checking {'eyr': '2024', 'cid': '225', 'iyr': '2018', 'pid': '522856696', 'byr': '1961', 'hcl': '#a97842', 'ecl': 'grn'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#866857', 'iyr': '1976', 'hgt': '190cm', 'byr': '1964', 'pid': '562135232', 'eyr': '2024', 'ecl': 'brn'}
|
||||
Checking {'eyr': '2024', 'byr': '1964', 'ecl': 'brn', 'iyr': '1976', 'hcl': '#866857', 'hgt': '190cm', 'pid': '562135232'}
|
||||
Bad issue year
|
||||
Checking {'eyr': '2022', 'hcl': 'z', 'iyr': '2011', 'hgt': '193cm', 'pid': '#6e4342', 'byr': '1936', 'cid': '296', 'ecl': '#3b8ed3'}
|
||||
Checking {'hgt': '193cm', 'pid': '#6e4342', 'iyr': '2011', 'byr': '1936', 'cid': '296', 'hcl': 'z', 'ecl': '#3b8ed3', 'eyr': '2022'}
|
||||
bad hair color
|
||||
Checking {'ecl': 'gry', 'hcl': '#efcc98', 'iyr': '2014', 'byr': '1985', 'pid': '503255860', 'eyr': '2023', 'cid': '154'}
|
||||
Checking {'cid': '154', 'byr': '1985', 'pid': '503255860', 'ecl': 'gry', 'eyr': '2023', 'hcl': '#efcc98', 'iyr': '2014'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#341e13', 'iyr': '2012', 'hgt': '154cm', 'pid': '631051435', 'byr': '1986', 'eyr': '2026', 'ecl': 'amb'}
|
||||
Checking {'eyr': '2035', 'hcl': '#623a2f', 'iyr': '2019', 'hgt': '155cm', 'pid': '318048681', 'byr': '1984', 'cid': '179', 'ecl': 'brn'}
|
||||
Checking {'eyr': '2026', 'iyr': '2012', 'pid': '631051435', 'byr': '1986', 'ecl': 'amb', 'hgt': '154cm', 'hcl': '#341e13'}
|
||||
Checking {'hcl': '#623a2f', 'pid': '318048681', 'ecl': 'brn', 'eyr': '2035', 'hgt': '155cm', 'cid': '179', 'byr': '1984', 'iyr': '2019'}
|
||||
Bad expire year
|
||||
Checking {'hcl': '#733820', 'iyr': '2013', 'hgt': '189cm', 'byr': '1969', 'pid': '185953891', 'eyr': '2024', 'ecl': 'amb'}
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '61cm', 'byr': '2012', 'pid': '33668114', 'ecl': '#38f2a6', 'eyr': '2021'}
|
||||
Checking {'iyr': '2013', 'hcl': '#733820', 'eyr': '2024', 'hgt': '189cm', 'ecl': 'amb', 'byr': '1969', 'pid': '185953891'}
|
||||
Checking {'hcl': '#cfa07d', 'ecl': '#38f2a6', 'iyr': '2013', 'hgt': '61cm', 'eyr': '2021', 'byr': '2012', 'pid': '33668114'}
|
||||
Bad birth year
|
||||
Checking {'cid': '51', 'hcl': '4946ca', 'iyr': '2019', 'hgt': '189', 'pid': '47030948', 'byr': '2013', 'ecl': '#1d136d', 'eyr': '2024'}
|
||||
Checking {'pid': '47030948', 'hcl': '4946ca', 'iyr': '2019', 'hgt': '189', 'ecl': '#1d136d', 'byr': '2013', 'eyr': '2024', 'cid': '51'}
|
||||
Bad birth year
|
||||
Checking {'eyr': '2020', 'hcl': '#c0946f', 'iyr': '2011', 'hgt': '162cm', 'byr': '1935', 'pid': '883047970', 'ecl': 'grn', 'cid': '51'}
|
||||
Checking {'cid': '221', 'hcl': '#623a2f', 'iyr': '2018', 'hgt': '155cm', 'pid': '013760919', 'byr': '1942', 'ecl': 'blu', 'eyr': '2020'}
|
||||
Checking {'hcl': '#7d3b0c', 'iyr': '1986', 'hgt': '152cm', 'pid': '29797863', 'byr': '2000', 'eyr': '2030', 'ecl': 'amb'}
|
||||
Checking {'ecl': 'grn', 'iyr': '2011', 'hgt': '162cm', 'byr': '1935', 'hcl': '#c0946f', 'pid': '883047970', 'cid': '51', 'eyr': '2020'}
|
||||
Checking {'pid': '013760919', 'iyr': '2018', 'byr': '1942', 'ecl': 'blu', 'hcl': '#623a2f', 'eyr': '2020', 'cid': '221', 'hgt': '155cm'}
|
||||
Checking {'hgt': '152cm', 'eyr': '2030', 'ecl': 'amb', 'iyr': '1986', 'hcl': '#7d3b0c', 'pid': '29797863', 'byr': '2000'}
|
||||
Bad issue year
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2013', 'hgt': '176cm', 'byr': '1995', 'pid': '546676799', 'ecl': 'brn', 'eyr': '2023'}
|
||||
Checking {'iyr': '2015', 'byr': '1955', 'pid': '634493767', 'eyr': '2028', 'ecl': 'oth'}
|
||||
Checking {'hgt': '176cm', 'byr': '1995', 'pid': '546676799', 'iyr': '2013', 'ecl': 'brn', 'hcl': '#fffffd', 'eyr': '2023'}
|
||||
Checking {'byr': '1955', 'pid': '634493767', 'eyr': '2028', 'iyr': '2015', 'ecl': 'oth'}
|
||||
Missing expected value
|
||||
Checking {'ecl': 'oth', 'hcl': '#7d3b0c', 'iyr': '2020', 'hgt': '174cm', 'pid': '893757190', 'byr': '2002', 'cid': '150', 'eyr': '2027'}
|
||||
Checking {'cid': '256', 'hcl': '#efcc98', 'iyr': '2012', 'hgt': '66in', 'pid': '790648045', 'byr': '1978', 'eyr': '2029', 'ecl': 'blu'}
|
||||
Checking {'ecl': 'hzl', 'hcl': '#0eeb2d', 'iyr': '2020', 'hgt': '155cm', 'byr': '1945', 'pid': '048725571', 'cid': '209', 'eyr': '2027'}
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2011', 'hgt': '162cm', 'byr': '2000', 'pid': '381372526', 'ecl': 'oth', 'eyr': '2023'}
|
||||
Checking {'hcl': '#602927', 'iyr': '2018', 'hgt': '171cm', 'pid': '544462408', 'byr': '1994', 'ecl': 'blu', 'eyr': '2030'}
|
||||
Checking {'eyr': '2025', 'hcl': '#733820', 'iyr': '2011', 'hgt': '187cm', 'pid': '533405863', 'byr': '1962', 'ecl': 'hzl', 'cid': '266'}
|
||||
Checking {'hcl': '#b6652a', 'iyr': '2019', 'hgt': '155cm', 'byr': '1975', 'pid': '967013712', 'eyr': '2029', 'ecl': 'oth'}
|
||||
Checking {'hcl': '#b6652a', 'iyr': '2010', 'hgt': '190cm', 'pid': '052112145', 'byr': '1982', 'eyr': '2022', 'ecl': 'amb'}
|
||||
Checking {'hcl': '#b6652a', 'iyr': '2012', 'hgt': '183cm', 'byr': '1950', 'pid': '946714779', 'ecl': 'hzl', 'eyr': '2030'}
|
||||
Checking {'cid': '103', 'hcl': '#ceb3a1', 'iyr': '2018', 'hgt': '70in', 'pid': '686010502', 'byr': '1993', 'ecl': 'gry', 'eyr': '2027'}
|
||||
Checking {'hcl': '#733820', 'iyr': '2012', 'byr': '1976', 'hgt': '157cm', 'eyr': '2030', 'ecl': 'gry'}
|
||||
Checking {'hcl': '#7d3b0c', 'iyr': '2020', 'cid': '150', 'hgt': '174cm', 'pid': '893757190', 'eyr': '2027', 'ecl': 'oth', 'byr': '2002'}
|
||||
Checking {'eyr': '2029', 'pid': '790648045', 'byr': '1978', 'iyr': '2012', 'hcl': '#efcc98', 'ecl': 'blu', 'hgt': '66in', 'cid': '256'}
|
||||
Checking {'iyr': '2020', 'byr': '1945', 'hgt': '155cm', 'cid': '209', 'eyr': '2027', 'hcl': '#0eeb2d', 'ecl': 'hzl', 'pid': '048725571'}
|
||||
Checking {'hcl': '#cfa07d', 'byr': '2000', 'iyr': '2011', 'pid': '381372526', 'ecl': 'oth', 'eyr': '2023', 'hgt': '162cm'}
|
||||
Checking {'ecl': 'blu', 'pid': '544462408', 'eyr': '2030', 'hgt': '171cm', 'iyr': '2018', 'hcl': '#602927', 'byr': '1994'}
|
||||
Checking {'hcl': '#733820', 'iyr': '2011', 'hgt': '187cm', 'ecl': 'hzl', 'pid': '533405863', 'byr': '1962', 'cid': '266', 'eyr': '2025'}
|
||||
Checking {'byr': '1975', 'hcl': '#b6652a', 'iyr': '2019', 'pid': '967013712', 'eyr': '2029', 'hgt': '155cm', 'ecl': 'oth'}
|
||||
Checking {'iyr': '2010', 'eyr': '2022', 'ecl': 'amb', 'pid': '052112145', 'byr': '1982', 'hgt': '190cm', 'hcl': '#b6652a'}
|
||||
Checking {'iyr': '2012', 'hgt': '183cm', 'hcl': '#b6652a', 'byr': '1950', 'ecl': 'hzl', 'pid': '946714779', 'eyr': '2030'}
|
||||
Checking {'eyr': '2027', 'pid': '686010502', 'cid': '103', 'byr': '1993', 'hcl': '#ceb3a1', 'ecl': 'gry', 'hgt': '70in', 'iyr': '2018'}
|
||||
Checking {'hcl': '#733820', 'iyr': '2012', 'hgt': '157cm', 'byr': '1976', 'eyr': '2030', 'ecl': 'gry'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#6b5442', 'iyr': '2017', 'hgt': '180cm', 'byr': '1955', 'pid': '732940101', 'ecl': 'hzl', 'eyr': '2022'}
|
||||
Checking {'eyr': '2024', 'hcl': '#18171d', 'iyr': '2010', 'hgt': '188cm', 'byr': '1924', 'pid': '905274031', 'cid': '299', 'ecl': 'oth'}
|
||||
Checking {'hcl': '#7f450a', 'iyr': '2013', 'hgt': '174cm', 'byr': '1999', 'pid': '021076124', 'eyr': '2024', 'ecl': 'gry'}
|
||||
Checking {'hcl': '#866857', 'iyr': '2016', 'hgt': '176cm', 'byr': '1940', 'pid': '398320693', 'ecl': 'oth', 'eyr': '2026'}
|
||||
Checking {'hcl': '#733820', 'iyr': '1931', 'pid': '158cm', 'hgt': '172cm', 'eyr': '2020', 'ecl': '#a0c290'}
|
||||
Checking {'ecl': 'hzl', 'byr': '1955', 'hgt': '180cm', 'iyr': '2017', 'eyr': '2022', 'hcl': '#6b5442', 'pid': '732940101'}
|
||||
Checking {'cid': '299', 'hgt': '188cm', 'byr': '1924', 'ecl': 'oth', 'pid': '905274031', 'iyr': '2010', 'eyr': '2024', 'hcl': '#18171d'}
|
||||
Checking {'eyr': '2024', 'hgt': '174cm', 'byr': '1999', 'iyr': '2013', 'pid': '021076124', 'hcl': '#7f450a', 'ecl': 'gry'}
|
||||
Checking {'hcl': '#866857', 'iyr': '2016', 'ecl': 'oth', 'hgt': '176cm', 'byr': '1940', 'pid': '398320693', 'eyr': '2026'}
|
||||
Checking {'hgt': '172cm', 'eyr': '2020', 'hcl': '#733820', 'iyr': '1931', 'ecl': '#a0c290', 'pid': '158cm'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#341e13', 'iyr': '2018', 'hgt': '182cm', 'byr': '1990', 'pid': '444561212', 'ecl': 'blu', 'eyr': '2025'}
|
||||
Checking {'hcl': '#602927', 'pid': '240732315', 'byr': '1976', 'hgt': '165cm', 'ecl': 'oth', 'eyr': '2023'}
|
||||
Checking {'ecl': 'blu', 'iyr': '2018', 'eyr': '2025', 'hcl': '#341e13', 'byr': '1990', 'pid': '444561212', 'hgt': '182cm'}
|
||||
Checking {'hcl': '#602927', 'hgt': '165cm', 'pid': '240732315', 'ecl': 'oth', 'eyr': '2023', 'byr': '1976'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#733820', 'iyr': '2016', 'hgt': '153cm', 'pid': '377612846', 'byr': '1967', 'ecl': 'brn', 'eyr': '2021'}
|
||||
Checking {'cid': '114', 'hcl': '#733820', 'iyr': '2018', 'hgt': '187cm', 'byr': '1925', 'pid': '207103786', 'eyr': '2030', 'ecl': 'blu'}
|
||||
Checking {'eyr': '2025', 'iyr': '2018', 'pid': '361909532', 'hgt': '184cm', 'ecl': 'blu', 'cid': '111'}
|
||||
Checking {'iyr': '2016', 'ecl': 'brn', 'pid': '377612846', 'eyr': '2021', 'byr': '1967', 'hcl': '#733820', 'hgt': '153cm'}
|
||||
Checking {'hgt': '187cm', 'iyr': '2018', 'eyr': '2030', 'ecl': 'blu', 'byr': '1925', 'hcl': '#733820', 'cid': '114', 'pid': '207103786'}
|
||||
Checking {'hgt': '184cm', 'ecl': 'blu', 'cid': '111', 'iyr': '2018', 'pid': '361909532', 'eyr': '2025'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#7d3b0c', 'iyr': '2019', 'hgt': '184cm', 'byr': '1968', 'pid': '381103495', 'ecl': 'grn', 'eyr': '2026'}
|
||||
Checking {'hcl': '#01adfd', 'iyr': '2019', 'byr': '1945', 'pid': '727826617', 'hgt': '151cm', 'eyr': '2020'}
|
||||
Checking {'ecl': 'grn', 'byr': '1968', 'iyr': '2019', 'hgt': '184cm', 'pid': '381103495', 'hcl': '#7d3b0c', 'eyr': '2026'}
|
||||
Checking {'iyr': '2019', 'byr': '1945', 'pid': '727826617', 'hcl': '#01adfd', 'eyr': '2020', 'hgt': '151cm'}
|
||||
Missing expected value
|
||||
Checking {'ecl': 'hzl', 'hcl': '#efcc98', 'iyr': '2011', 'hgt': '171cm', 'byr': '1924', 'pid': '235809608', 'eyr': '2029', 'cid': '280'}
|
||||
Checking {'cid': '97', 'hcl': '#602927', 'iyr': '2010', 'hgt': '172cm', 'byr': '1973', 'pid': '599786261', 'eyr': '2029', 'ecl': 'gry'}
|
||||
Checking {'hcl': '#866857', 'iyr': '2017', 'hgt': '163cm', 'pid': '768895320', 'byr': '1940', 'eyr': '2027', 'ecl': 'oth'}
|
||||
Checking {'hcl': '#6b5442', 'iyr': '2013', 'byr': '1959', 'pid': '823221334', 'hgt': '178cm'}
|
||||
Checking {'cid': '280', 'iyr': '2011', 'hcl': '#efcc98', 'ecl': 'hzl', 'eyr': '2029', 'byr': '1924', 'hgt': '171cm', 'pid': '235809608'}
|
||||
Checking {'hcl': '#602927', 'byr': '1973', 'pid': '599786261', 'eyr': '2029', 'hgt': '172cm', 'iyr': '2010', 'ecl': 'gry', 'cid': '97'}
|
||||
Checking {'iyr': '2017', 'eyr': '2027', 'pid': '768895320', 'hgt': '163cm', 'hcl': '#866857', 'byr': '1940', 'ecl': 'oth'}
|
||||
Checking {'hgt': '178cm', 'hcl': '#6b5442', 'iyr': '2013', 'byr': '1959', 'pid': '823221334'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2024', 'hcl': '#da8af3', 'iyr': '2014', 'hgt': '150cm', 'pid': '534201972', 'byr': '1945', 'ecl': 'hzl', 'cid': '263'}
|
||||
Checking {'cid': '341', 'hcl': '#efcc98', 'iyr': '2010', 'hgt': '189cm', 'pid': '469575516', 'byr': '1994', 'eyr': '2025', 'ecl': 'blu'}
|
||||
Checking {'hcl': '#888785', 'iyr': '2015', 'hgt': '60in', 'byr': '1999', 'pid': '797138561', 'cid': '167', 'eyr': '2024'}
|
||||
Checking {'iyr': '2014', 'pid': '534201972', 'ecl': 'hzl', 'hgt': '150cm', 'hcl': '#da8af3', 'byr': '1945', 'cid': '263', 'eyr': '2024'}
|
||||
Checking {'pid': '469575516', 'hgt': '189cm', 'byr': '1994', 'eyr': '2025', 'iyr': '2010', 'ecl': 'blu', 'hcl': '#efcc98', 'cid': '341'}
|
||||
Checking {'cid': '167', 'eyr': '2024', 'byr': '1999', 'pid': '797138561', 'hcl': '#888785', 'hgt': '60in', 'iyr': '2015'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2023', 'hcl': '#866857', 'iyr': '2014', 'hgt': '174cm', 'pid': '909549652', 'byr': '1967', 'cid': '103', 'ecl': 'amb'}
|
||||
Checking {'eyr': '2027', 'iyr': '2016', 'hgt': '61in', 'pid': '813003671', 'byr': '1995', 'ecl': 'oth', 'cid': '95'}
|
||||
Checking {'iyr': '2014', 'hcl': '#866857', 'cid': '103', 'pid': '909549652', 'byr': '1967', 'hgt': '174cm', 'ecl': 'amb', 'eyr': '2023'}
|
||||
Checking {'pid': '813003671', 'ecl': 'oth', 'hgt': '61in', 'cid': '95', 'iyr': '2016', 'byr': '1995', 'eyr': '2027'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2014', 'hgt': '166cm', 'pid': '000088706', 'byr': '1951', 'eyr': '2021', 'ecl': 'blu'}
|
||||
Checking {'eyr': '2022', 'hcl': '#18171d', 'iyr': '2017', 'hgt': '162cm', 'byr': '1941', 'pid': '511728076', 'cid': '287', 'ecl': 'grn'}
|
||||
Checking {'hcl': '#18171d', 'iyr': '2017', 'hgt': '191cm', 'pid': '209898040', 'byr': '1968', 'eyr': '2025', 'ecl': 'brn'}
|
||||
Checking {'eyr': '2004', 'hcl': 'z', 'iyr': '2016', 'hgt': '190cm', 'byr': '1932', 'pid': '#02dfcc', 'cid': '201', 'ecl': '#6b9341'}
|
||||
Checking {'eyr': '2021', 'hcl': '#fffffd', 'pid': '000088706', 'iyr': '2014', 'ecl': 'blu', 'hgt': '166cm', 'byr': '1951'}
|
||||
Checking {'cid': '287', 'ecl': 'grn', 'byr': '1941', 'iyr': '2017', 'hcl': '#18171d', 'hgt': '162cm', 'pid': '511728076', 'eyr': '2022'}
|
||||
Checking {'pid': '209898040', 'byr': '1968', 'eyr': '2025', 'hcl': '#18171d', 'ecl': 'brn', 'iyr': '2017', 'hgt': '191cm'}
|
||||
Checking {'byr': '1932', 'hcl': 'z', 'hgt': '190cm', 'cid': '201', 'iyr': '2016', 'pid': '#02dfcc', 'ecl': '#6b9341', 'eyr': '2004'}
|
||||
Bad expire year
|
||||
Checking {'hcl': '#ceb3a1', 'iyr': '2013', 'hgt': '191cm', 'pid': '501799813', 'byr': '1993', 'ecl': 'hzl', 'eyr': '2020'}
|
||||
Checking {'cid': '315', 'hcl': '#a97842', 'iyr': '2012', 'hgt': '179cm', 'pid': '897450687', 'byr': '1984', 'eyr': '2029', 'ecl': 'blu'}
|
||||
Checking {'hcl': '#6b5442', 'iyr': '2011', 'hgt': '190in', 'pid': '299193732', 'byr': '1945', 'ecl': 'gry', 'eyr': '2020'}
|
||||
Checking {'iyr': '2013', 'hcl': '#ceb3a1', 'hgt': '191cm', 'pid': '501799813', 'ecl': 'hzl', 'byr': '1993', 'eyr': '2020'}
|
||||
Checking {'ecl': 'blu', 'cid': '315', 'pid': '897450687', 'hgt': '179cm', 'byr': '1984', 'eyr': '2029', 'iyr': '2012', 'hcl': '#a97842'}
|
||||
Checking {'iyr': '2011', 'ecl': 'gry', 'hcl': '#6b5442', 'pid': '299193732', 'eyr': '2020', 'byr': '1945', 'hgt': '190in'}
|
||||
bad height in inches: 190
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2017', 'hgt': '158cm', 'pid': '090738381', 'byr': '1992', 'eyr': '2022', 'ecl': 'oth'}
|
||||
Checking {'cid': '92', 'hcl': '#573edf', 'iyr': '2016', 'hgt': '179cm', 'pid': '765588435', 'byr': '2002', 'ecl': 'amb', 'eyr': '2028'}
|
||||
Checking {'hcl': '#967d2f', 'iyr': '2015', 'pid': '128081454', 'hgt': '190cm', 'eyr': '2025', 'ecl': 'oth'}
|
||||
Checking {'hgt': '158cm', 'eyr': '2022', 'pid': '090738381', 'byr': '1992', 'iyr': '2017', 'hcl': '#fffffd', 'ecl': 'oth'}
|
||||
Checking {'eyr': '2028', 'cid': '92', 'ecl': 'amb', 'hcl': '#573edf', 'pid': '765588435', 'iyr': '2016', 'hgt': '179cm', 'byr': '2002'}
|
||||
Checking {'eyr': '2025', 'pid': '128081454', 'hcl': '#967d2f', 'hgt': '190cm', 'iyr': '2015', 'ecl': 'oth'}
|
||||
Missing expected value
|
||||
Checking {'cid': '239', 'hcl': '#888785', 'iyr': '2019', 'hgt': '189cm', 'byr': '1993', 'pid': '001825574', 'eyr': '2025', 'ecl': 'gry'}
|
||||
Checking {'hcl': 'z', 'iyr': '1971', 'hgt': '100', 'byr': '2013', 'pid': '0758189515', 'eyr': '2034', 'ecl': 'gry'}
|
||||
Checking {'hgt': '189cm', 'eyr': '2025', 'ecl': 'gry', 'hcl': '#888785', 'byr': '1993', 'pid': '001825574', 'cid': '239', 'iyr': '2019'}
|
||||
Checking {'byr': '2013', 'pid': '0758189515', 'hcl': 'z', 'eyr': '2034', 'iyr': '1971', 'ecl': 'gry', 'hgt': '100'}
|
||||
Bad birth year
|
||||
Checking {'hcl': '#3638a2', 'iyr': '2011', 'hgt': '156cm', 'byr': '1943', 'pid': '539139386', 'eyr': '2026', 'ecl': 'hzl'}
|
||||
Checking {'hcl': '#733820', 'iyr': '2017', 'hgt': '173cm', 'pid': '016597738', 'byr': '1956', 'eyr': '2030', 'ecl': 'brn'}
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2018', 'hgt': '167cm', 'pid': '822607758', 'byr': '1974', 'eyr': '2028', 'ecl': 'brn'}
|
||||
Checking {'hcl': '#efcc98', 'iyr': '2020', 'hgt': '65in', 'byr': '1980', 'pid': '397182705', 'eyr': '2020', 'ecl': 'oth'}
|
||||
Checking {'hcl': '#ceb3a1', 'iyr': '2015', 'byr': '1954', 'pid': '398087239', 'eyr': '2024'}
|
||||
Checking {'eyr': '2026', 'byr': '1943', 'hcl': '#3638a2', 'iyr': '2011', 'pid': '539139386', 'hgt': '156cm', 'ecl': 'hzl'}
|
||||
Checking {'eyr': '2030', 'pid': '016597738', 'iyr': '2017', 'hgt': '173cm', 'ecl': 'brn', 'hcl': '#733820', 'byr': '1956'}
|
||||
Checking {'eyr': '2028', 'iyr': '2018', 'pid': '822607758', 'hcl': '#cfa07d', 'ecl': 'brn', 'hgt': '167cm', 'byr': '1974'}
|
||||
Checking {'eyr': '2020', 'byr': '1980', 'hgt': '65in', 'iyr': '2020', 'ecl': 'oth', 'hcl': '#efcc98', 'pid': '397182705'}
|
||||
Checking {'iyr': '2015', 'byr': '1954', 'hcl': '#ceb3a1', 'eyr': '2024', 'pid': '398087239'}
|
||||
Missing expected value
|
||||
Checking {'ecl': 'zzz', 'hcl': '234fc4', 'iyr': '2015', 'hgt': '177in', 'pid': '159cm', 'byr': '2022', 'eyr': '2027', 'cid': '256'}
|
||||
Checking {'cid': '256', 'hcl': '234fc4', 'ecl': 'zzz', 'hgt': '177in', 'eyr': '2027', 'iyr': '2015', 'pid': '159cm', 'byr': '2022'}
|
||||
Bad birth year
|
||||
Checking {'eyr': '2025', 'hcl': '#a928b0', 'iyr': '2018', 'hgt': '158cm', 'byr': '1976', 'pid': '920448637', 'cid': '209', 'ecl': 'hzl'}
|
||||
Checking {'cid': '223', 'hcl': '#888785', 'iyr': '2016', 'hgt': '165cm', 'pid': '96925844', 'byr': '1984', 'eyr': '2030', 'ecl': 'gry'}
|
||||
Checking {'iyr': '2018', 'cid': '209', 'hcl': '#a928b0', 'byr': '1976', 'ecl': 'hzl', 'pid': '920448637', 'eyr': '2025', 'hgt': '158cm'}
|
||||
Checking {'pid': '96925844', 'iyr': '2016', 'eyr': '2030', 'hcl': '#888785', 'ecl': 'gry', 'byr': '1984', 'cid': '223', 'hgt': '165cm'}
|
||||
bad pid
|
||||
Checking {'hcl': '#18171d', 'iyr': '2014', 'hgt': '153cm', 'byr': '1964', 'pid': '831479208', 'eyr': '2024', 'ecl': 'brn'}
|
||||
Checking {'hcl': '#ceb3a1', 'iyr': '2019', 'hgt': '185cm', 'byr': '1958', 'pid': '827043482', 'ecl': 'brn', 'eyr': '2026'}
|
||||
Checking {'eyr': '2026', 'hcl': '#733820', 'iyr': '2020', 'hgt': '67in', 'pid': '426593479', 'byr': '1922', 'cid': '116', 'ecl': 'blu'}
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2019', 'hgt': '156cm', 'pid': '951768959', 'byr': '1969', 'eyr': '2022', 'cid': '330'}
|
||||
Checking {'byr': '1964', 'pid': '831479208', 'hgt': '153cm', 'iyr': '2014', 'eyr': '2024', 'ecl': 'brn', 'hcl': '#18171d'}
|
||||
Checking {'iyr': '2019', 'ecl': 'brn', 'hgt': '185cm', 'byr': '1958', 'hcl': '#ceb3a1', 'eyr': '2026', 'pid': '827043482'}
|
||||
Checking {'iyr': '2020', 'hgt': '67in', 'cid': '116', 'hcl': '#733820', 'ecl': 'blu', 'pid': '426593479', 'byr': '1922', 'eyr': '2026'}
|
||||
Checking {'eyr': '2022', 'hcl': '#fffffd', 'cid': '330', 'pid': '951768959', 'byr': '1969', 'iyr': '2019', 'hgt': '156cm'}
|
||||
Missing expected value
|
||||
Checking {'ecl': 'oth', 'hcl': '#111544', 'iyr': '2019', 'hgt': '151cm', 'byr': '1929', 'pid': '083495633', 'cid': '223', 'eyr': '2030'}
|
||||
Checking {'iyr': '2016', 'byr': '1967', 'pid': '739606431', 'hgt': '166cm', 'eyr': '2025', 'ecl': 'blu'}
|
||||
Checking {'eyr': '2030', 'ecl': 'oth', 'byr': '1929', 'hgt': '151cm', 'cid': '223', 'hcl': '#111544', 'pid': '083495633', 'iyr': '2019'}
|
||||
Checking {'eyr': '2025', 'iyr': '2016', 'ecl': 'blu', 'hgt': '166cm', 'byr': '1967', 'pid': '739606431'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#ceb3a1', 'iyr': '2020', 'hgt': '161cm', 'pid': '788420638', 'byr': '1922', 'eyr': '2021', 'ecl': 'gry'}
|
||||
Checking {'hcl': '#888785', 'byr': '1956', 'pid': '705051840', 'hgt': '158cm', 'eyr': '2025', 'ecl': 'oth'}
|
||||
Checking {'eyr': '2021', 'ecl': 'gry', 'hcl': '#ceb3a1', 'pid': '788420638', 'byr': '1922', 'iyr': '2020', 'hgt': '161cm'}
|
||||
Checking {'byr': '1956', 'eyr': '2025', 'hcl': '#888785', 'ecl': 'oth', 'pid': '705051840', 'hgt': '158cm'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2015', 'pid': '047851403', 'byr': '1937', 'hgt': '192cm', 'eyr': '2025'}
|
||||
Checking {'pid': '047851403', 'byr': '1937', 'hcl': '#cfa07d', 'iyr': '2015', 'hgt': '192cm', 'eyr': '2025'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2022', 'hcl': '#c0946f', 'iyr': '2019', 'hgt': '178cm', 'byr': '1923', 'pid': '411527076', 'cid': '194', 'ecl': 'gry'}
|
||||
Checking {'hcl': '#341e13', 'iyr': '2014', 'hgt': '186cm', 'byr': '1956', 'pid': '976268893', 'eyr': '2027', 'ecl': 'brn'}
|
||||
Checking {'eyr': '2025', 'hcl': '#18171d', 'iyr': '2011', 'hgt': '183cm', 'byr': '1958', 'pid': '389943720', 'cid': '81', 'ecl': 'brn'}
|
||||
Checking {'hcl': '#c0946f', 'byr': '1972', 'pid': '593351635', 'hgt': '165cm', 'eyr': '2028', 'ecl': 'amb'}
|
||||
Checking {'hgt': '178cm', 'cid': '194', 'iyr': '2019', 'byr': '1923', 'hcl': '#c0946f', 'pid': '411527076', 'ecl': 'gry', 'eyr': '2022'}
|
||||
Checking {'hgt': '186cm', 'iyr': '2014', 'byr': '1956', 'eyr': '2027', 'ecl': 'brn', 'pid': '976268893', 'hcl': '#341e13'}
|
||||
Checking {'iyr': '2011', 'cid': '81', 'hcl': '#18171d', 'hgt': '183cm', 'byr': '1958', 'ecl': 'brn', 'eyr': '2025', 'pid': '389943720'}
|
||||
Checking {'eyr': '2028', 'byr': '1972', 'ecl': 'amb', 'hcl': '#c0946f', 'pid': '593351635', 'hgt': '165cm'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#341e13', 'iyr': '2012', 'hgt': '169cm', 'byr': '1991', 'pid': '599766528', 'ecl': 'blu', 'cid': '156'}
|
||||
Checking {'iyr': '2012', 'byr': '1991', 'ecl': 'blu', 'hcl': '#341e13', 'hgt': '169cm', 'cid': '156', 'pid': '599766528'}
|
||||
Missing expected value
|
||||
Checking {'ecl': 'zzz', 'iyr': '2001', 'hgt': '75cm', 'byr': '2029', 'pid': '319443119', 'eyr': '2020', 'cid': '306'}
|
||||
Checking {'byr': '2029', 'hgt': '75cm', 'pid': '319443119', 'iyr': '2001', 'eyr': '2020', 'cid': '306', 'ecl': 'zzz'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2021', 'hcl': '#866857', 'iyr': '2014', 'hgt': '167cm', 'byr': '1948', 'pid': '256331758', 'cid': '273', 'ecl': 'grn'}
|
||||
Checking {'cid': '241', 'hcl': '#733820', 'iyr': '2016', 'hgt': '158cm', 'byr': '1977', 'pid': '423680717', 'eyr': '2024', 'ecl': 'oth'}
|
||||
Checking {'eyr': '2024', 'hcl': '#341e13', 'iyr': '2017', 'hgt': '185cm', 'pid': '788619400', 'byr': '1954', 'ecl': 'hzl', 'cid': '153'}
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2016', 'hgt': '161cm', 'pid': '621023569', 'byr': '1928', 'ecl': 'blu', 'eyr': '2026'}
|
||||
Checking {'ecl': 'xry', 'hcl': 'aa8fc8', 'iyr': '1951', 'hgt': '168in', 'byr': '2024', 'pid': '166cm', 'eyr': '1979', 'cid': '91'}
|
||||
Checking {'hcl': '#866857', 'cid': '273', 'ecl': 'grn', 'byr': '1948', 'hgt': '167cm', 'iyr': '2014', 'pid': '256331758', 'eyr': '2021'}
|
||||
Checking {'iyr': '2016', 'eyr': '2024', 'ecl': 'oth', 'hcl': '#733820', 'byr': '1977', 'pid': '423680717', 'hgt': '158cm', 'cid': '241'}
|
||||
Checking {'hcl': '#341e13', 'pid': '788619400', 'byr': '1954', 'ecl': 'hzl', 'cid': '153', 'hgt': '185cm', 'eyr': '2024', 'iyr': '2017'}
|
||||
Checking {'hcl': '#cfa07d', 'ecl': 'blu', 'hgt': '161cm', 'eyr': '2026', 'pid': '621023569', 'byr': '1928', 'iyr': '2016'}
|
||||
Checking {'cid': '91', 'byr': '2024', 'hgt': '168in', 'iyr': '1951', 'ecl': 'xry', 'eyr': '1979', 'hcl': 'aa8fc8', 'pid': '166cm'}
|
||||
Bad birth year
|
||||
Checking {'cid': '155', 'hcl': '#18171d', 'iyr': '2012', 'hgt': '159cm', 'byr': '1952', 'pid': '875326712', 'ecl': 'brn', 'eyr': '2028'}
|
||||
Checking {'hcl': '#733820', 'iyr': '2015', 'hgt': '163cm', 'byr': '1990', 'pid': '162682954', 'eyr': '2026', 'ecl': 'amb'}
|
||||
Checking {'hcl': '#c0946f', 'iyr': '2020', 'hgt': '151cm', 'pid': '936952728', 'byr': '1969', 'ecl': 'brn', 'eyr': '2029'}
|
||||
Checking {'hcl': '#866857', 'iyr': '2013', 'hgt': '189cm', 'pid': '132928469', 'byr': '1928', 'ecl': 'amb', 'eyr': '2026'}
|
||||
Checking {'hcl': '#623a2f', 'iyr': '2012', 'hgt': '190cm', 'pid': '185240766', 'byr': '1952', 'ecl': 'grn', 'eyr': '2020'}
|
||||
Checking {'cid': '64', 'hcl': 'z', 'iyr': '1935', 'hgt': '67cm', 'byr': '2021', 'pid': '4900748653', 'eyr': '2026', 'ecl': '#ef67e5'}
|
||||
Checking {'eyr': '2028', 'cid': '155', 'hgt': '159cm', 'byr': '1952', 'pid': '875326712', 'ecl': 'brn', 'iyr': '2012', 'hcl': '#18171d'}
|
||||
Checking {'eyr': '2026', 'hcl': '#733820', 'byr': '1990', 'hgt': '163cm', 'ecl': 'amb', 'iyr': '2015', 'pid': '162682954'}
|
||||
Checking {'iyr': '2020', 'pid': '936952728', 'byr': '1969', 'ecl': 'brn', 'hgt': '151cm', 'hcl': '#c0946f', 'eyr': '2029'}
|
||||
Checking {'hgt': '189cm', 'pid': '132928469', 'ecl': 'amb', 'hcl': '#866857', 'byr': '1928', 'eyr': '2026', 'iyr': '2013'}
|
||||
Checking {'ecl': 'grn', 'pid': '185240766', 'iyr': '2012', 'hgt': '190cm', 'byr': '1952', 'hcl': '#623a2f', 'eyr': '2020'}
|
||||
Checking {'byr': '2021', 'eyr': '2026', 'hgt': '67cm', 'ecl': '#ef67e5', 'hcl': 'z', 'iyr': '1935', 'pid': '4900748653', 'cid': '64'}
|
||||
Bad birth year
|
||||
Checking {'ecl': 'gry', 'hcl': '#7d3b0c', 'iyr': '2016', 'hgt': '69in', 'pid': '076116194', 'byr': '1979', 'cid': '248', 'eyr': '2022'}
|
||||
Checking {'cid': '127', 'hcl': '#44e350', 'iyr': '2020', 'hgt': '180cm', 'byr': '1991', 'ecl': 'blu', 'eyr': '2021'}
|
||||
Checking {'hgt': '69in', 'hcl': '#7d3b0c', 'cid': '248', 'eyr': '2022', 'pid': '076116194', 'byr': '1979', 'ecl': 'gry', 'iyr': '2016'}
|
||||
Checking {'byr': '1991', 'eyr': '2021', 'hgt': '180cm', 'iyr': '2020', 'cid': '127', 'ecl': 'blu', 'hcl': '#44e350'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#733820', 'iyr': '2018', 'hgt': '150cm', 'byr': '1954', 'pid': '002868205', 'ecl': 'brn', 'eyr': '2021'}
|
||||
Checking {'ecl': 'amb', 'hcl': '#623a2f', 'iyr': '2017', 'hgt': '170cm', 'pid': '524531652', 'byr': '1927', 'eyr': '2020', 'cid': '80'}
|
||||
Checking {'ecl': 'blu', 'hcl': '#efcc98', 'iyr': '2018', 'hgt': '187cm', 'pid': '424660272', 'byr': '1970', 'eyr': '2021', 'cid': '238'}
|
||||
Checking {'eyr': '2020', 'hcl': '#602927', 'iyr': '2013', 'hgt': '175cm', 'byr': '1923', 'pid': '946014113', 'cid': '273', 'ecl': 'brn'}
|
||||
Checking {'eyr': '2022', 'hcl': '#6b5442', 'iyr': '2012', 'hgt': '71in', 'byr': '1929', 'pid': '581329373', 'cid': '88', 'ecl': 'gry'}
|
||||
Checking {'ecl': 'oth', 'hcl': '#6b5442', 'iyr': '2017', 'hgt': '184', 'pid': '022131529', 'byr': '2005', 'cid': '79', 'eyr': '1960'}
|
||||
Checking {'byr': '1954', 'hcl': '#733820', 'iyr': '2018', 'pid': '002868205', 'hgt': '150cm', 'ecl': 'brn', 'eyr': '2021'}
|
||||
Checking {'pid': '524531652', 'hcl': '#623a2f', 'cid': '80', 'ecl': 'amb', 'iyr': '2017', 'eyr': '2020', 'hgt': '170cm', 'byr': '1927'}
|
||||
Checking {'pid': '424660272', 'iyr': '2018', 'hcl': '#efcc98', 'eyr': '2021', 'cid': '238', 'hgt': '187cm', 'byr': '1970', 'ecl': 'blu'}
|
||||
Checking {'byr': '1923', 'pid': '946014113', 'cid': '273', 'iyr': '2013', 'hgt': '175cm', 'ecl': 'brn', 'hcl': '#602927', 'eyr': '2020'}
|
||||
Checking {'hcl': '#6b5442', 'cid': '88', 'ecl': 'gry', 'iyr': '2012', 'byr': '1929', 'hgt': '71in', 'eyr': '2022', 'pid': '581329373'}
|
||||
Checking {'eyr': '1960', 'ecl': 'oth', 'iyr': '2017', 'pid': '022131529', 'cid': '79', 'hgt': '184', 'byr': '2005', 'hcl': '#6b5442'}
|
||||
Bad birth year
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2011', 'hgt': '60in', 'pid': '422677836', 'byr': '1925', 'eyr': '2030', 'ecl': 'gry'}
|
||||
Checking {'eyr': '2026', 'hcl': '#18171d', 'iyr': '2011', 'hgt': '158cm', 'byr': '1971', 'pid': '517329528', 'cid': '325', 'ecl': 'hzl'}
|
||||
Checking {'eyr': '2030', 'iyr': '2017', 'hgt': '176cm', 'byr': '1937', 'pid': '321795494', 'ecl': 'blu', 'cid': '259'}
|
||||
Checking {'eyr': '2030', 'pid': '422677836', 'iyr': '2011', 'hcl': '#fffffd', 'byr': '1925', 'hgt': '60in', 'ecl': 'gry'}
|
||||
Checking {'cid': '325', 'hgt': '158cm', 'byr': '1971', 'ecl': 'hzl', 'pid': '517329528', 'hcl': '#18171d', 'eyr': '2026', 'iyr': '2011'}
|
||||
Checking {'byr': '1937', 'cid': '259', 'eyr': '2030', 'hgt': '176cm', 'ecl': 'blu', 'pid': '321795494', 'iyr': '2017'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2026', 'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '74in', 'pid': '551525002', 'byr': '1954', 'cid': '230', 'ecl': 'grn'}
|
||||
Checking {'cid': '139', 'hcl': 'c39522', 'pid': '004366607', 'hgt': '66cm', 'ecl': '#21a3e9', 'eyr': '2024'}
|
||||
Checking {'pid': '551525002', 'ecl': 'grn', 'eyr': '2026', 'iyr': '2013', 'cid': '230', 'hgt': '74in', 'hcl': '#cfa07d', 'byr': '1954'}
|
||||
Checking {'pid': '004366607', 'hcl': 'c39522', 'hgt': '66cm', 'ecl': '#21a3e9', 'eyr': '2024', 'cid': '139'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2037', 'hcl': '0ee9d4', 'iyr': '1994', 'hgt': '158cm', 'byr': '2016', 'pid': '522572315', 'cid': '98', 'ecl': 'xry'}
|
||||
Checking {'ecl': 'xry', 'eyr': '2037', 'byr': '2016', 'iyr': '1994', 'cid': '98', 'pid': '522572315', 'hgt': '158cm', 'hcl': '0ee9d4'}
|
||||
Bad birth year
|
||||
Checking {'eyr': '2028', 'hcl': '#142217', 'iyr': '2018', 'hgt': '179cm', 'pid': '073189127', 'byr': '1977', 'ecl': 'grn', 'cid': '70'}
|
||||
Checking {'ecl': 'brn', 'hcl': '#733820', 'iyr': '2020', 'hgt': '64in', 'pid': '045852463', 'byr': '1948', 'eyr': '2020', 'cid': '69'}
|
||||
Checking {'ecl': 'brn', 'hcl': '#733820', 'iyr': '2011', 'hgt': '178cm', 'byr': '1970', 'pid': '512594967', 'cid': '268', 'eyr': '2025'}
|
||||
Checking {'hcl': '#18171d', 'iyr': '2014', 'byr': '1950', 'pid': '329927551', 'hgt': '161cm', 'eyr': '2025'}
|
||||
Checking {'cid': '70', 'eyr': '2028', 'hgt': '179cm', 'pid': '073189127', 'ecl': 'grn', 'iyr': '2018', 'hcl': '#142217', 'byr': '1977'}
|
||||
Checking {'pid': '045852463', 'cid': '69', 'iyr': '2020', 'ecl': 'brn', 'byr': '1948', 'eyr': '2020', 'hgt': '64in', 'hcl': '#733820'}
|
||||
Checking {'cid': '268', 'byr': '1970', 'eyr': '2025', 'hgt': '178cm', 'pid': '512594967', 'iyr': '2011', 'ecl': 'brn', 'hcl': '#733820'}
|
||||
Checking {'eyr': '2025', 'hcl': '#18171d', 'iyr': '2014', 'byr': '1950', 'hgt': '161cm', 'pid': '329927551'}
|
||||
Missing expected value
|
||||
Checking {'cid': '100', 'hcl': '#a97842', 'iyr': '2010', 'hgt': '163cm', 'byr': '1956', 'pid': '965746490', 'eyr': '2024', 'ecl': 'brn'}
|
||||
Checking {'ecl': 'grn', 'hcl': '#602927', 'iyr': '2011', 'hgt': '190cm', 'pid': '864571411', 'byr': '1962', 'cid': '112', 'eyr': '2027'}
|
||||
Checking {'cid': '54', 'hcl': '#6b5442', 'iyr': '2011', 'hgt': '159cm', 'byr': '1922', 'pid': '689641249', 'eyr': '2025', 'ecl': 'gry'}
|
||||
Checking {'cid': '323', 'iyr': '2020', 'hgt': '158cm', 'pid': '876082513', 'byr': '1941', 'ecl': 'hzl', 'eyr': '2028'}
|
||||
Checking {'byr': '1956', 'eyr': '2024', 'hgt': '163cm', 'pid': '965746490', 'hcl': '#a97842', 'ecl': 'brn', 'cid': '100', 'iyr': '2010'}
|
||||
Checking {'cid': '112', 'eyr': '2027', 'pid': '864571411', 'hgt': '190cm', 'iyr': '2011', 'byr': '1962', 'ecl': 'grn', 'hcl': '#602927'}
|
||||
Checking {'ecl': 'gry', 'cid': '54', 'iyr': '2011', 'hcl': '#6b5442', 'byr': '1922', 'eyr': '2025', 'pid': '689641249', 'hgt': '159cm'}
|
||||
Checking {'eyr': '2028', 'cid': '323', 'iyr': '2020', 'hgt': '158cm', 'ecl': 'hzl', 'pid': '876082513', 'byr': '1941'}
|
||||
Missing expected value
|
||||
Checking {'cid': '226', 'hcl': '#18171d', 'iyr': '2014', 'hgt': '160cm', 'pid': '910116712', 'byr': '1927', 'ecl': 'oth', 'eyr': '2023'}
|
||||
Checking {'ecl': 'grn', 'hcl': '#602927', 'iyr': '2030', 'hgt': '186cm', 'byr': '1963', 'pid': '706533329', 'cid': '183', 'eyr': '2030'}
|
||||
Checking {'hcl': '#18171d', 'hgt': '160cm', 'pid': '910116712', 'ecl': 'oth', 'iyr': '2014', 'byr': '1927', 'eyr': '2023', 'cid': '226'}
|
||||
Checking {'iyr': '2030', 'hcl': '#602927', 'eyr': '2030', 'ecl': 'grn', 'cid': '183', 'hgt': '186cm', 'byr': '1963', 'pid': '706533329'}
|
||||
Bad issue year
|
||||
Checking {'ecl': 'hzl', 'hcl': '#866857', 'iyr': '2015', 'hgt': '150cm', 'byr': '1958', 'pid': '120633047', 'cid': '279', 'eyr': '2026'}
|
||||
Checking {'hcl': '#733820', 'iyr': '2019', 'hgt': '187cm', 'byr': '1989', 'pid': '470596304', 'ecl': 'hzl', 'eyr': '2022'}
|
||||
Checking {'cid': '346', 'hcl': '#888785', 'iyr': '2013', 'hgt': '167cm', 'byr': '1994', 'pid': '528844948', 'ecl': 'hzl', 'eyr': '2027'}
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2014', 'hgt': '192cm', 'pid': '969181309', 'byr': '1970', 'eyr': '2025', 'ecl': 'amb'}
|
||||
Checking {'hcl': '#341e13', 'iyr': '2012', 'hgt': '167cm', 'pid': '053348609', 'byr': '1931', 'eyr': '2026', 'ecl': 'oth'}
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2013', 'hgt': '182cm', 'pid': '030276279', 'byr': '1967', 'eyr': '2029', 'ecl': 'grn'}
|
||||
Checking {'cid': '224', 'hcl': '#ceb3a1', 'iyr': '2016', 'hgt': '177cm', 'byr': '1949', 'pid': '745439371', 'eyr': '2022', 'ecl': 'oth'}
|
||||
Checking {'hcl': '#341e13', 'iyr': '2016', 'hgt': '64in', 'byr': '1940', 'pid': '351021541', 'eyr': '2028', 'ecl': 'amb'}
|
||||
Checking {'eyr': '2021', 'hcl': '#866857', 'iyr': '2019', 'hgt': '74in', 'pid': '698666542', 'byr': '1953', 'cid': '309', 'ecl': 'oth'}
|
||||
Checking {'ecl': 'brn', 'hcl': '#733820', 'iyr': '2013', 'hgt': '186cm', 'byr': '1979', 'pid': '727367898', 'cid': '236', 'eyr': '2023'}
|
||||
Checking {'cid': '245', 'hcl': '#623a2f', 'iyr': '2016', 'hgt': '65cm', 'byr': '1956', 'pid': '371685442', 'eyr': '2025', 'ecl': 'oth'}
|
||||
Checking {'cid': '279', 'eyr': '2026', 'iyr': '2015', 'byr': '1958', 'pid': '120633047', 'hgt': '150cm', 'ecl': 'hzl', 'hcl': '#866857'}
|
||||
Checking {'iyr': '2019', 'byr': '1989', 'hcl': '#733820', 'ecl': 'hzl', 'pid': '470596304', 'hgt': '187cm', 'eyr': '2022'}
|
||||
Checking {'eyr': '2027', 'hcl': '#888785', 'cid': '346', 'iyr': '2013', 'hgt': '167cm', 'ecl': 'hzl', 'byr': '1994', 'pid': '528844948'}
|
||||
Checking {'hcl': '#fffffd', 'pid': '969181309', 'iyr': '2014', 'hgt': '192cm', 'eyr': '2025', 'byr': '1970', 'ecl': 'amb'}
|
||||
Checking {'eyr': '2026', 'iyr': '2012', 'hcl': '#341e13', 'ecl': 'oth', 'pid': '053348609', 'byr': '1931', 'hgt': '167cm'}
|
||||
Checking {'eyr': '2029', 'ecl': 'grn', 'pid': '030276279', 'iyr': '2013', 'hgt': '182cm', 'hcl': '#fffffd', 'byr': '1967'}
|
||||
Checking {'byr': '1949', 'eyr': '2022', 'hcl': '#ceb3a1', 'iyr': '2016', 'ecl': 'oth', 'hgt': '177cm', 'cid': '224', 'pid': '745439371'}
|
||||
Checking {'iyr': '2016', 'byr': '1940', 'eyr': '2028', 'pid': '351021541', 'hcl': '#341e13', 'ecl': 'amb', 'hgt': '64in'}
|
||||
Checking {'cid': '309', 'hgt': '74in', 'pid': '698666542', 'hcl': '#866857', 'ecl': 'oth', 'byr': '1953', 'iyr': '2019', 'eyr': '2021'}
|
||||
Checking {'iyr': '2013', 'byr': '1979', 'eyr': '2023', 'hgt': '186cm', 'ecl': 'brn', 'cid': '236', 'pid': '727367898', 'hcl': '#733820'}
|
||||
Checking {'hgt': '65cm', 'byr': '1956', 'eyr': '2025', 'pid': '371685442', 'iyr': '2016', 'ecl': 'oth', 'cid': '245', 'hcl': '#623a2f'}
|
||||
bad height in cm
|
||||
Checking {'hcl': '#888785', 'iyr': '2010', 'hgt': '155cm', 'byr': '1927', 'pid': '916070590', 'ecl': 'grn', 'eyr': '2027'}
|
||||
Checking {'eyr': '2022', 'hcl': '#866857', 'iyr': '2019', 'hgt': '179cm', 'byr': '1993', 'pid': '354895012', 'ecl': 'blu', 'cid': '332'}
|
||||
Checking {'eyr': '2025', 'hcl': '#efcc98', 'iyr': '2029', 'hgt': '69cm', 'pid': '179cm', 'byr': '2007', 'cid': '216', 'ecl': 'oth'}
|
||||
Checking {'hgt': '155cm', 'ecl': 'grn', 'hcl': '#888785', 'eyr': '2027', 'iyr': '2010', 'byr': '1927', 'pid': '916070590'}
|
||||
Checking {'hgt': '179cm', 'ecl': 'blu', 'hcl': '#866857', 'byr': '1993', 'iyr': '2019', 'cid': '332', 'eyr': '2022', 'pid': '354895012'}
|
||||
Checking {'iyr': '2029', 'hgt': '69cm', 'hcl': '#efcc98', 'pid': '179cm', 'cid': '216', 'byr': '2007', 'ecl': 'oth', 'eyr': '2025'}
|
||||
Bad birth year
|
||||
Checking {'hcl': 'z', 'iyr': '1988', 'hgt': '187', 'byr': '2020', 'pid': '225115160', 'ecl': '#30e67c', 'eyr': '2037'}
|
||||
Checking {'iyr': '1988', 'hgt': '187', 'hcl': 'z', 'ecl': '#30e67c', 'byr': '2020', 'pid': '225115160', 'eyr': '2037'}
|
||||
Bad birth year
|
||||
Checking {'iyr': '2011', 'byr': '1965', 'pid': '455044780', 'hgt': '188cm', 'eyr': '2021', 'ecl': 'hzl'}
|
||||
Checking {'eyr': '2021', 'iyr': '2011', 'hgt': '188cm', 'ecl': 'hzl', 'byr': '1965', 'pid': '455044780'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2016', 'hgt': '61in', 'pid': '750994177', 'byr': '2002', 'ecl': 'gry', 'eyr': '2023'}
|
||||
Checking {'hcl': '#18171d', 'iyr': '2020', 'hgt': '177cm', 'pid': '304482618', 'byr': '1955', 'ecl': 'gry', 'eyr': '2027'}
|
||||
Checking {'ecl': 'oth', 'hcl': '#b6652a', 'iyr': '2017', 'hgt': '187cm', 'byr': '1981', 'pid': '795201673', 'eyr': '2020', 'cid': '154'}
|
||||
Checking {'cid': '101', 'hcl': '#cfa07d', 'iyr': '2019', 'hgt': '151cm', 'byr': '1954', 'pid': '930011749', 'eyr': '2026', 'ecl': 'gry'}
|
||||
Checking {'eyr': '1955', 'hcl': 'z', 'iyr': '2030', 'pid': '#d45ed4', 'byr': '1999', 'cid': '338', 'ecl': 'zzz'}
|
||||
Checking {'ecl': 'gry', 'pid': '750994177', 'byr': '2002', 'iyr': '2016', 'eyr': '2023', 'hgt': '61in', 'hcl': '#fffffd'}
|
||||
Checking {'iyr': '2020', 'ecl': 'gry', 'pid': '304482618', 'hcl': '#18171d', 'eyr': '2027', 'byr': '1955', 'hgt': '177cm'}
|
||||
Checking {'hgt': '187cm', 'byr': '1981', 'pid': '795201673', 'eyr': '2020', 'cid': '154', 'hcl': '#b6652a', 'iyr': '2017', 'ecl': 'oth'}
|
||||
Checking {'ecl': 'gry', 'byr': '1954', 'hgt': '151cm', 'iyr': '2019', 'cid': '101', 'eyr': '2026', 'hcl': '#cfa07d', 'pid': '930011749'}
|
||||
Checking {'ecl': 'zzz', 'eyr': '1955', 'pid': '#d45ed4', 'cid': '338', 'iyr': '2030', 'hcl': 'z', 'byr': '1999'}
|
||||
Missing expected value
|
||||
Checking {'cid': '125', 'hcl': '#7d3b0c', 'iyr': '2018', 'hgt': '166cm', 'pid': '861636258', 'byr': '1958', 'eyr': '2020', 'ecl': 'brn'}
|
||||
Checking {'hcl': '#7d3b0c', 'iyr': '2014', 'hgt': '67', 'byr': '1935', 'pid': '409864761', 'eyr': '2022', 'ecl': 'brn'}
|
||||
Checking {'eyr': '2020', 'pid': '861636258', 'hgt': '166cm', 'hcl': '#7d3b0c', 'ecl': 'brn', 'iyr': '2018', 'cid': '125', 'byr': '1958'}
|
||||
Checking {'iyr': '2014', 'eyr': '2022', 'hgt': '67', 'hcl': '#7d3b0c', 'ecl': 'brn', 'byr': '1935', 'pid': '409864761'}
|
||||
bad height generally
|
||||
Checking {'eyr': '2022', 'hcl': '#866857', 'iyr': '2012', 'hgt': '178cm', 'pid': '483584137', 'byr': '2000', 'cid': '94', 'ecl': 'blu'}
|
||||
Checking {'hcl': '#602927', 'iyr': '2015', 'hgt': '184cm', 'byr': '1946', 'pid': '947292495', 'ecl': 'hzl', 'eyr': '2028'}
|
||||
Checking {'ecl': 'gry', 'hcl': '#6b5442', 'iyr': '2014', 'hgt': '59in', 'byr': '1974', 'pid': '358779220', 'cid': '96', 'eyr': '2028'}
|
||||
Checking {'eyr': '2022', 'hcl': '#61154f', 'byr': '1932', 'hgt': '167cm', 'ecl': 'brn', 'cid': '126'}
|
||||
Checking {'hcl': '#866857', 'iyr': '2012', 'cid': '94', 'pid': '483584137', 'byr': '2000', 'ecl': 'blu', 'hgt': '178cm', 'eyr': '2022'}
|
||||
Checking {'byr': '1946', 'ecl': 'hzl', 'iyr': '2015', 'eyr': '2028', 'hgt': '184cm', 'hcl': '#602927', 'pid': '947292495'}
|
||||
Checking {'byr': '1974', 'cid': '96', 'hgt': '59in', 'eyr': '2028', 'pid': '358779220', 'hcl': '#6b5442', 'ecl': 'gry', 'iyr': '2014'}
|
||||
Checking {'hcl': '#61154f', 'byr': '1932', 'hgt': '167cm', 'ecl': 'brn', 'cid': '126', 'eyr': '2022'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#866857', 'iyr': '2014', 'hgt': '169cm', 'byr': '1926', 'pid': '463772660', 'ecl': 'gry', 'eyr': '2020'}
|
||||
Checking {'cid': '111', 'hcl': '#fffffd', 'iyr': '2010', 'hgt': '191cm', 'pid': '654733578', 'byr': '1943', 'eyr': '2024', 'ecl': 'hzl'}
|
||||
Checking {'hcl': '#c0946f', 'iyr': '2026', 'pid': '164776417', 'byr': '1977', 'hgt': '74cm', 'eyr': '2021'}
|
||||
Checking {'ecl': 'gry', 'iyr': '2014', 'hgt': '169cm', 'byr': '1926', 'eyr': '2020', 'hcl': '#866857', 'pid': '463772660'}
|
||||
Checking {'pid': '654733578', 'ecl': 'hzl', 'cid': '111', 'iyr': '2010', 'hcl': '#fffffd', 'eyr': '2024', 'hgt': '191cm', 'byr': '1943'}
|
||||
Checking {'eyr': '2021', 'hgt': '74cm', 'hcl': '#c0946f', 'iyr': '2026', 'pid': '164776417', 'byr': '1977'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '1949', 'hcl': 'z', 'iyr': '1921', 'pid': '442332495', 'byr': '2018', 'ecl': '#6db74f', 'cid': '101'}
|
||||
Checking {'ecl': '#6db74f', 'iyr': '1921', 'pid': '442332495', 'byr': '2018', 'hcl': 'z', 'cid': '101', 'eyr': '1949'}
|
||||
Missing expected value
|
||||
Checking {'ecl': 'blu', 'hcl': '518816', 'iyr': '1939', 'hgt': '191cm', 'byr': '2022', 'pid': '10107923', 'eyr': '2038', 'cid': '332'}
|
||||
Checking {'cid': '332', 'byr': '2022', 'ecl': 'blu', 'eyr': '2038', 'iyr': '1939', 'hcl': '518816', 'hgt': '191cm', 'pid': '10107923'}
|
||||
Bad birth year
|
||||
Checking {'hcl': '#733820', 'iyr': '2010', 'hgt': '183cm', 'pid': '168853141', 'byr': '1996', 'eyr': '2021', 'ecl': 'hzl'}
|
||||
Checking {'cid': '89', 'hcl': '336a3b', 'iyr': '2016', 'hgt': '62in', 'pid': '556617728', 'byr': '2029', 'eyr': '2023', 'ecl': 'xry'}
|
||||
Checking {'pid': '168853141', 'iyr': '2010', 'eyr': '2021', 'byr': '1996', 'ecl': 'hzl', 'hgt': '183cm', 'hcl': '#733820'}
|
||||
Checking {'hgt': '62in', 'pid': '556617728', 'hcl': '336a3b', 'eyr': '2023', 'byr': '2029', 'ecl': 'xry', 'iyr': '2016', 'cid': '89'}
|
||||
Bad birth year
|
||||
Checking {'eyr': '2023', 'hcl': '#efcc98', 'iyr': '2020', 'hgt': '181cm', 'pid': '075811396', 'byr': '1960', 'ecl': 'hzl', 'cid': '297'}
|
||||
Checking {'hcl': '#602927', 'iyr': '2015', 'byr': '1995', 'hgt': '75in', 'eyr': '2030', 'ecl': 'brn'}
|
||||
Checking {'ecl': 'hzl', 'hcl': '#efcc98', 'iyr': '2020', 'cid': '297', 'hgt': '181cm', 'pid': '075811396', 'eyr': '2023', 'byr': '1960'}
|
||||
Checking {'eyr': '2030', 'hcl': '#602927', 'ecl': 'brn', 'iyr': '2015', 'hgt': '75in', 'byr': '1995'}
|
||||
Missing expected value
|
||||
Checking {'cid': '237', 'hcl': '#8936bb', 'iyr': '2015', 'hgt': '183cm', 'byr': '1998', 'eyr': '2028', 'ecl': 'grn'}
|
||||
Checking {'ecl': 'grn', 'cid': '237', 'hcl': '#8936bb', 'hgt': '183cm', 'eyr': '2028', 'iyr': '2015', 'byr': '1998'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#efcc98', 'pid': '550427102', 'byr': '1991', 'hgt': '67in', 'ecl': 'gry'}
|
||||
Checking {'pid': '550427102', 'hgt': '67in', 'byr': '1991', 'ecl': 'gry', 'hcl': '#efcc98'}
|
||||
Missing expected value
|
||||
Checking {'ecl': 'gmt', 'hcl': '00f05b', 'iyr': '2022', 'hgt': '70cm', 'byr': '1948', 'cid': '274', 'eyr': '1961'}
|
||||
Checking {'cid': '274', 'hgt': '70cm', 'iyr': '2022', 'eyr': '1961', 'hcl': '00f05b', 'byr': '1948', 'ecl': 'gmt'}
|
||||
Missing expected value
|
||||
Checking {'cid': '150', 'hcl': '#18171d', 'iyr': '2018', 'hgt': '153cm', 'pid': '831302208', 'byr': '1927', 'ecl': 'blu', 'eyr': '2020'}
|
||||
Checking {'ecl': 'blu', 'hcl': '#ceb3a1', 'iyr': '2018', 'hgt': '192cm', 'byr': '1973', 'pid': '770473271', 'cid': '215', 'eyr': '2027'}
|
||||
Checking {'hcl': '#623a2f', 'iyr': '2019', 'hgt': '174cm', 'byr': '1962', 'pid': '589533254', 'eyr': '2021', 'ecl': 'hzl'}
|
||||
Checking {'hcl': '#a97842', 'iyr': '2012', 'hgt': '184cm', 'byr': '1991', 'pid': '677889195', 'ecl': 'hzl', 'cid': '292'}
|
||||
Checking {'ecl': 'blu', 'iyr': '2018', 'hgt': '153cm', 'eyr': '2020', 'pid': '831302208', 'byr': '1927', 'hcl': '#18171d', 'cid': '150'}
|
||||
Checking {'iyr': '2018', 'byr': '1973', 'hcl': '#ceb3a1', 'cid': '215', 'hgt': '192cm', 'pid': '770473271', 'eyr': '2027', 'ecl': 'blu'}
|
||||
Checking {'iyr': '2019', 'eyr': '2021', 'hcl': '#623a2f', 'ecl': 'hzl', 'hgt': '174cm', 'byr': '1962', 'pid': '589533254'}
|
||||
Checking {'iyr': '2012', 'ecl': 'hzl', 'hgt': '184cm', 'cid': '292', 'byr': '1991', 'pid': '677889195', 'hcl': '#a97842'}
|
||||
Missing expected value
|
||||
Checking {'hcl': 'z', 'iyr': '2010', 'hgt': '154in', 'pid': '#4f47c3', 'byr': '2022', 'cid': '69', 'ecl': '#e36a65'}
|
||||
Checking {'iyr': '2010', 'pid': '#4f47c3', 'hgt': '154in', 'cid': '69', 'hcl': 'z', 'byr': '2022', 'ecl': '#e36a65'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#b6652a', 'iyr': '2016', 'hgt': '171cm', 'pid': '499582878', 'byr': '1930', 'ecl': '#5ff50c', 'eyr': '2024'}
|
||||
Checking {'ecl': '#5ff50c', 'pid': '499582878', 'hcl': '#b6652a', 'hgt': '171cm', 'iyr': '2016', 'byr': '1930', 'eyr': '2024'}
|
||||
bad eye color
|
||||
Checking {'hcl': '#6b5442', 'iyr': '2015', 'hgt': '159cm', 'byr': '1936', 'pid': '658019126', 'eyr': '2028', 'ecl': 'amb'}
|
||||
Checking {'cid': '239', 'hcl': '#18171d', 'iyr': '2013', 'hgt': '158cm', 'byr': '1928', 'pid': '599970280', 'eyr': '2026', 'ecl': 'grn'}
|
||||
Checking {'hcl': '#c0946f', 'iyr': '2018', 'pid': '684820830', 'hgt': '182cm', 'ecl': 'oth', 'eyr': '2023'}
|
||||
Checking {'hgt': '159cm', 'byr': '1936', 'eyr': '2028', 'hcl': '#6b5442', 'ecl': 'amb', 'iyr': '2015', 'pid': '658019126'}
|
||||
Checking {'byr': '1928', 'pid': '599970280', 'eyr': '2026', 'ecl': 'grn', 'hgt': '158cm', 'hcl': '#18171d', 'cid': '239', 'iyr': '2013'}
|
||||
Checking {'pid': '684820830', 'hgt': '182cm', 'ecl': 'oth', 'hcl': '#c0946f', 'eyr': '2023', 'iyr': '2018'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2021', 'hcl': '#602927', 'iyr': '2019', 'hgt': '71in', 'pid': '668361647', 'byr': '1952', 'ecl': 'blu', 'cid': '348'}
|
||||
Checking {'cid': '193', 'hcl': '#7d5994', 'iyr': '2010', 'hgt': '165cm', 'pid': '256350027', 'byr': '1947', 'ecl': 'grn', 'eyr': '2030'}
|
||||
Checking {'eyr': '2029', 'hcl': '#602927', 'iyr': '2019', 'hgt': '153cm', 'byr': '1931', 'pid': '911300650', 'cid': '118', 'ecl': 'gry'}
|
||||
Checking {'hcl': '#866857', 'iyr': '2016', 'hgt': '154cm', 'pid': '515526226', 'byr': '1936', 'eyr': '2025', 'ecl': 'grn'}
|
||||
Checking {'hcl': '#623a2f', 'iyr': '2019', 'hgt': '160cm', 'pid': '932621460', 'byr': '1990', 'ecl': 'oth', 'eyr': '2030'}
|
||||
Checking {'eyr': '2027', 'hcl': '#623a2f', 'iyr': '2016', 'hgt': '176cm', 'pid': '662549708', 'byr': '1949', 'cid': '277', 'ecl': 'blu'}
|
||||
Checking {'iyr': '2010', 'byr': '1947', 'pid': '223603325', 'eyr': '2021', 'ecl': 'gry'}
|
||||
Checking {'iyr': '2019', 'ecl': 'blu', 'pid': '668361647', 'cid': '348', 'byr': '1952', 'hcl': '#602927', 'eyr': '2021', 'hgt': '71in'}
|
||||
Checking {'hgt': '165cm', 'ecl': 'grn', 'eyr': '2030', 'iyr': '2010', 'pid': '256350027', 'hcl': '#7d5994', 'cid': '193', 'byr': '1947'}
|
||||
Checking {'hcl': '#602927', 'iyr': '2019', 'ecl': 'gry', 'eyr': '2029', 'byr': '1931', 'cid': '118', 'hgt': '153cm', 'pid': '911300650'}
|
||||
Checking {'eyr': '2025', 'hgt': '154cm', 'hcl': '#866857', 'iyr': '2016', 'ecl': 'grn', 'pid': '515526226', 'byr': '1936'}
|
||||
Checking {'hcl': '#623a2f', 'hgt': '160cm', 'iyr': '2019', 'ecl': 'oth', 'pid': '932621460', 'eyr': '2030', 'byr': '1990'}
|
||||
Checking {'hcl': '#623a2f', 'ecl': 'blu', 'eyr': '2027', 'cid': '277', 'pid': '662549708', 'byr': '1949', 'iyr': '2016', 'hgt': '176cm'}
|
||||
Checking {'iyr': '2010', 'eyr': '2021', 'byr': '1947', 'pid': '223603325', 'ecl': 'gry'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#733820', 'iyr': '2020', 'hgt': '183cm', 'pid': '145738978', 'byr': '1949', 'ecl': 'gry', 'eyr': '2029'}
|
||||
Checking {'hcl': '#a97842', 'iyr': '2011', 'hgt': '63in', 'byr': '1941', 'pid': '091089766', 'eyr': '2028', 'ecl': 'gry'}
|
||||
Checking {'eyr': '2021', 'hcl': '#fffffd', 'iyr': '2020', 'hgt': '157cm', 'byr': '1978', 'pid': '242258232', 'ecl': 'hzl', 'cid': '275'}
|
||||
Checking {'cid': '132', 'hcl': '#733820', 'iyr': '2011', 'hgt': '192cm', 'pid': '239061408', 'byr': '1949', 'ecl': 'oth', 'eyr': '2023'}
|
||||
Checking {'eyr': '2021', 'hcl': '#341e13', 'iyr': '2014', 'hgt': '152cm', 'byr': '1954', 'pid': '667414305', 'cid': '282', 'ecl': 'brn'}
|
||||
Checking {'hcl': '#7d3b0c', 'iyr': '2018', 'hgt': '186cm', 'pid': '745564182', 'byr': '1935', 'eyr': '2028', 'ecl': 'gry'}
|
||||
Checking {'hcl': 'd26483', 'iyr': '2014', 'hgt': '163cm', 'byr': '1972', 'pid': '611712147', 'eyr': '2026', 'ecl': '#57d27c'}
|
||||
Checking {'ecl': 'gry', 'pid': '145738978', 'eyr': '2029', 'iyr': '2020', 'hcl': '#733820', 'byr': '1949', 'hgt': '183cm'}
|
||||
Checking {'hgt': '63in', 'eyr': '2028', 'iyr': '2011', 'hcl': '#a97842', 'byr': '1941', 'ecl': 'gry', 'pid': '091089766'}
|
||||
Checking {'hcl': '#fffffd', 'cid': '275', 'hgt': '157cm', 'eyr': '2021', 'byr': '1978', 'ecl': 'hzl', 'iyr': '2020', 'pid': '242258232'}
|
||||
Checking {'pid': '239061408', 'ecl': 'oth', 'eyr': '2023', 'iyr': '2011', 'hgt': '192cm', 'byr': '1949', 'hcl': '#733820', 'cid': '132'}
|
||||
Checking {'byr': '1954', 'hgt': '152cm', 'ecl': 'brn', 'pid': '667414305', 'eyr': '2021', 'cid': '282', 'iyr': '2014', 'hcl': '#341e13'}
|
||||
Checking {'iyr': '2018', 'pid': '745564182', 'hgt': '186cm', 'eyr': '2028', 'hcl': '#7d3b0c', 'byr': '1935', 'ecl': 'gry'}
|
||||
Checking {'iyr': '2014', 'eyr': '2026', 'hcl': 'd26483', 'byr': '1972', 'pid': '611712147', 'hgt': '163cm', 'ecl': '#57d27c'}
|
||||
bad hair color
|
||||
Checking {'eyr': '2025', 'hcl': '#cfa07d', 'iyr': '2020', 'hgt': '158cm', 'byr': '1937', 'pid': '150255302', 'ecl': 'blu', 'cid': '322'}
|
||||
Checking {'cid': '116', 'hcl': '#866857', 'iyr': '2011', 'hgt': '155cm', 'byr': '1974', 'pid': '755213661', 'eyr': '2030', 'ecl': 'blu'}
|
||||
Checking {'hcl': '#866857', 'iyr': '2014', 'hgt': '166cm', 'pid': '679616797', 'byr': '1999', 'ecl': 'gry', 'eyr': '2025'}
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2019', 'pid': '835993614', 'byr': '1920', 'hgt': '158cm', 'eyr': '2028'}
|
||||
Checking {'cid': '322', 'eyr': '2025', 'byr': '1937', 'iyr': '2020', 'ecl': 'blu', 'hcl': '#cfa07d', 'hgt': '158cm', 'pid': '150255302'}
|
||||
Checking {'eyr': '2030', 'iyr': '2011', 'hcl': '#866857', 'byr': '1974', 'ecl': 'blu', 'pid': '755213661', 'hgt': '155cm', 'cid': '116'}
|
||||
Checking {'hcl': '#866857', 'pid': '679616797', 'ecl': 'gry', 'hgt': '166cm', 'byr': '1999', 'iyr': '2014', 'eyr': '2025'}
|
||||
Checking {'iyr': '2019', 'hcl': '#fffffd', 'hgt': '158cm', 'eyr': '2028', 'pid': '835993614', 'byr': '1920'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2025', 'hcl': '#200aaa', 'iyr': '2013', 'hgt': '151cm', 'pid': '742320152', 'byr': '1931', 'cid': '63', 'ecl': 'brn'}
|
||||
Checking {'ecl': 'xry', 'hcl': '#615954', 'iyr': '2014', 'hgt': '150cm', 'byr': '1950', 'pid': '596469710', 'eyr': '2027', 'cid': '155'}
|
||||
Checking {'ecl': 'brn', 'pid': '742320152', 'iyr': '2013', 'hgt': '151cm', 'eyr': '2025', 'cid': '63', 'byr': '1931', 'hcl': '#200aaa'}
|
||||
Checking {'byr': '1950', 'cid': '155', 'ecl': 'xry', 'hgt': '150cm', 'iyr': '2014', 'eyr': '2027', 'hcl': '#615954', 'pid': '596469710'}
|
||||
bad eye color
|
||||
Checking {'eyr': '2021', 'hcl': '#18171d', 'iyr': '2016', 'hgt': '166cm', 'byr': '1946', 'pid': '267318602', 'ecl': 'gry', 'cid': '261'}
|
||||
Checking {'hcl': '#b6652a', 'iyr': '2013', 'hgt': '185cm', 'pid': '092573029', 'byr': '1956', 'ecl': 'gry', 'eyr': '2023'}
|
||||
Checking {'hcl': '#efcc98', 'iyr': '2014', 'hgt': '172cm', 'byr': '1997', 'pid': '337403043', 'eyr': '2021', 'ecl': 'blu'}
|
||||
Checking {'iyr': '2015', 'byr': '1949', 'pid': '230935940', 'hgt': '190cm', 'eyr': '2023'}
|
||||
Checking {'byr': '1946', 'hgt': '166cm', 'ecl': 'gry', 'hcl': '#18171d', 'cid': '261', 'iyr': '2016', 'pid': '267318602', 'eyr': '2021'}
|
||||
Checking {'ecl': 'gry', 'hgt': '185cm', 'iyr': '2013', 'pid': '092573029', 'eyr': '2023', 'byr': '1956', 'hcl': '#b6652a'}
|
||||
Checking {'byr': '1997', 'hgt': '172cm', 'eyr': '2021', 'iyr': '2014', 'pid': '337403043', 'ecl': 'blu', 'hcl': '#efcc98'}
|
||||
Checking {'hgt': '190cm', 'iyr': '2015', 'byr': '1949', 'eyr': '2023', 'pid': '230935940'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#a97842', 'iyr': '2017', 'hgt': '171cm', 'byr': '1980', 'pid': '9435249395', 'eyr': '2021', 'ecl': 'oth'}
|
||||
Checking {'byr': '1980', 'hgt': '171cm', 'eyr': '2021', 'pid': '9435249395', 'ecl': 'oth', 'hcl': '#a97842', 'iyr': '2017'}
|
||||
bad pid
|
||||
Checking {'cid': '93', 'hcl': '#b6652a', 'iyr': '1923', 'hgt': '186cm', 'byr': '2011', 'pid': '239188418', 'eyr': '2039', 'ecl': 'hzl'}
|
||||
Checking {'byr': '2011', 'hcl': '#b6652a', 'eyr': '2039', 'ecl': 'hzl', 'iyr': '1923', 'hgt': '186cm', 'pid': '239188418', 'cid': '93'}
|
||||
Bad birth year
|
||||
Checking {'eyr': '2028', 'hcl': '#602927', 'iyr': '2020', 'hgt': '160cm', 'pid': '791787662', 'byr': '1975', 'cid': '51', 'ecl': 'gry'}
|
||||
Checking {'hcl': '#a97842', 'iyr': '2016', 'hgt': '183cm', 'pid': '720900081', 'byr': '1978', 'ecl': 'amb', 'eyr': '2022'}
|
||||
Checking {'cid': '345', 'hcl': '#18171d', 'iyr': '2017', 'hgt': '157cm', 'pid': '628454234', 'byr': '1988', 'eyr': '2027', 'ecl': 'gry'}
|
||||
Checking {'hcl': '#341e13', 'iyr': '2013', 'hgt': '66in', 'byr': '1985', 'pid': '996422540', 'ecl': 'grn', 'eyr': '2020'}
|
||||
Checking {'cid': '214', 'hcl': '#866857', 'iyr': '2017', 'hgt': '161cm', 'pid': '186cm', 'byr': '1988', 'ecl': 'brn', 'eyr': '2022'}
|
||||
Checking {'pid': '791787662', 'cid': '51', 'ecl': 'gry', 'hcl': '#602927', 'hgt': '160cm', 'iyr': '2020', 'eyr': '2028', 'byr': '1975'}
|
||||
Checking {'ecl': 'amb', 'pid': '720900081', 'byr': '1978', 'hcl': '#a97842', 'hgt': '183cm', 'iyr': '2016', 'eyr': '2022'}
|
||||
Checking {'eyr': '2027', 'hgt': '157cm', 'pid': '628454234', 'hcl': '#18171d', 'ecl': 'gry', 'iyr': '2017', 'cid': '345', 'byr': '1988'}
|
||||
Checking {'byr': '1985', 'pid': '996422540', 'iyr': '2013', 'hgt': '66in', 'ecl': 'grn', 'eyr': '2020', 'hcl': '#341e13'}
|
||||
Checking {'eyr': '2022', 'pid': '186cm', 'cid': '214', 'iyr': '2017', 'hcl': '#866857', 'ecl': 'brn', 'byr': '1988', 'hgt': '161cm'}
|
||||
bad pid
|
||||
Checking {'ecl': 'grn', 'hcl': '#18171d', 'iyr': '2019', 'hgt': '154cm', 'pid': '752184592', 'byr': '1966', 'eyr': '2025', 'cid': '119'}
|
||||
Checking {'eyr': '2024', 'hcl': '#b6652a', 'iyr': '2011', 'hgt': '59in', 'byr': '1974', 'pid': '477922277', 'ecl': 'grn', 'cid': '100'}
|
||||
Checking {'hcl': '#6b5442', 'iyr': '2013', 'hgt': '184cm', 'byr': '1969', 'pid': '514127885', 'ecl': 'brn', 'eyr': '2023'}
|
||||
Checking {'cid': '111', 'hcl': '#cfa07d', 'iyr': '2020', 'hgt': '64in', 'byr': '1923', 'ecl': 'gry', 'eyr': '2029'}
|
||||
Checking {'iyr': '2019', 'eyr': '2025', 'pid': '752184592', 'hgt': '154cm', 'byr': '1966', 'hcl': '#18171d', 'cid': '119', 'ecl': 'grn'}
|
||||
Checking {'hcl': '#b6652a', 'cid': '100', 'byr': '1974', 'pid': '477922277', 'eyr': '2024', 'ecl': 'grn', 'iyr': '2011', 'hgt': '59in'}
|
||||
Checking {'iyr': '2013', 'ecl': 'brn', 'hgt': '184cm', 'eyr': '2023', 'byr': '1969', 'pid': '514127885', 'hcl': '#6b5442'}
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2020', 'byr': '1923', 'ecl': 'gry', 'hgt': '64in', 'eyr': '2029', 'cid': '111'}
|
||||
Missing expected value
|
||||
Checking {'ecl': 'blu', 'hcl': '#866857', 'iyr': '2016', 'hgt': '73in', 'byr': '1921', 'pid': '971490088', 'eyr': '2025', 'cid': '271'}
|
||||
Checking {'cid': '63', 'hcl': '#602927', 'iyr': '2019', 'hgt': '179cm', 'byr': '1953', 'pid': '226869705', 'ecl': 'oth', 'eyr': '2023'}
|
||||
Checking {'hcl': '#341e13', 'iyr': '2010', 'hgt': '175cm', 'byr': '1938', 'pid': '718683561', 'ecl': 'hzl', 'eyr': '2021'}
|
||||
Checking {'hcl': 'z', 'iyr': '2023', 'hgt': '189in', 'byr': '2030', 'pid': '171cm', 'ecl': '#447c00', 'eyr': '2022'}
|
||||
Checking {'byr': '1921', 'hgt': '73in', 'pid': '971490088', 'iyr': '2016', 'eyr': '2025', 'hcl': '#866857', 'cid': '271', 'ecl': 'blu'}
|
||||
Checking {'ecl': 'oth', 'eyr': '2023', 'iyr': '2019', 'hgt': '179cm', 'byr': '1953', 'pid': '226869705', 'hcl': '#602927', 'cid': '63'}
|
||||
Checking {'hgt': '175cm', 'ecl': 'hzl', 'iyr': '2010', 'byr': '1938', 'eyr': '2021', 'pid': '718683561', 'hcl': '#341e13'}
|
||||
Checking {'iyr': '2023', 'hgt': '189in', 'byr': '2030', 'pid': '171cm', 'ecl': '#447c00', 'hcl': 'z', 'eyr': '2022'}
|
||||
Bad birth year
|
||||
Checking {'cid': '99', 'hcl': '#888785', 'iyr': '2020', 'hgt': '191cm', 'pid': '128824091', 'byr': '1982', 'ecl': 'blu', 'eyr': '2026'}
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2017', 'hgt': '151cm', 'pid': '333173949', 'byr': '1928', 'eyr': '2026', 'ecl': 'oth'}
|
||||
Checking {'cid': '168', 'hcl': '#6b5442', 'iyr': '2016', 'hgt': '158cm', 'byr': '1945', 'pid': '888990994', 'eyr': '2026', 'ecl': 'grn'}
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '168cm', 'byr': '1931', 'pid': '716975878', 'ecl': 'grn', 'eyr': '2023'}
|
||||
Checking {'hcl': '#888785', 'iyr': '2020', 'hgt': '161cm', 'pid': '815050555', 'byr': '1980', 'ecl': 'blu', 'eyr': '2025'}
|
||||
Checking {'hcl': '#7d3b0c', 'iyr': '2017', 'hgt': '171cm', 'pid': '470039281', 'byr': '1967', 'ecl': 'gry', 'eyr': '2021'}
|
||||
Checking {'hcl': '#bdf8d6', 'iyr': '2018', 'hgt': '184cm', 'byr': '1954', 'pid': '694267794', 'eyr': '2030', 'ecl': 'blu'}
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2016', 'hgt': '167cm', 'byr': '1971', 'pid': '237865320', 'ecl': 'brn', 'eyr': '2027'}
|
||||
Checking {'cid': '215', 'hcl': '#a97842', 'iyr': '2014', 'hgt': '176cm', 'byr': '1921', 'pid': '186145415', 'ecl': 'oth', 'eyr': '2028'}
|
||||
Checking {'hcl': '#7d3b0c', 'pid': '925805272', 'hgt': '65in', 'eyr': '2030', 'ecl': 'blu'}
|
||||
Checking {'ecl': 'blu', 'eyr': '2026', 'hgt': '191cm', 'iyr': '2020', 'hcl': '#888785', 'pid': '128824091', 'cid': '99', 'byr': '1982'}
|
||||
Checking {'eyr': '2026', 'pid': '333173949', 'iyr': '2017', 'ecl': 'oth', 'byr': '1928', 'hcl': '#fffffd', 'hgt': '151cm'}
|
||||
Checking {'hcl': '#6b5442', 'ecl': 'grn', 'byr': '1945', 'pid': '888990994', 'cid': '168', 'eyr': '2026', 'iyr': '2016', 'hgt': '158cm'}
|
||||
Checking {'ecl': 'grn', 'iyr': '2013', 'byr': '1931', 'pid': '716975878', 'hgt': '168cm', 'hcl': '#cfa07d', 'eyr': '2023'}
|
||||
Checking {'pid': '815050555', 'ecl': 'blu', 'hgt': '161cm', 'hcl': '#888785', 'eyr': '2025', 'iyr': '2020', 'byr': '1980'}
|
||||
Checking {'pid': '470039281', 'byr': '1967', 'iyr': '2017', 'ecl': 'gry', 'eyr': '2021', 'hgt': '171cm', 'hcl': '#7d3b0c'}
|
||||
Checking {'hcl': '#bdf8d6', 'iyr': '2018', 'byr': '1954', 'eyr': '2030', 'ecl': 'blu', 'hgt': '184cm', 'pid': '694267794'}
|
||||
Checking {'hcl': '#cfa07d', 'byr': '1971', 'ecl': 'brn', 'iyr': '2016', 'hgt': '167cm', 'eyr': '2027', 'pid': '237865320'}
|
||||
Checking {'byr': '1921', 'eyr': '2028', 'iyr': '2014', 'pid': '186145415', 'cid': '215', 'ecl': 'oth', 'hgt': '176cm', 'hcl': '#a97842'}
|
||||
Checking {'pid': '925805272', 'hcl': '#7d3b0c', 'eyr': '2030', 'hgt': '65in', 'ecl': 'blu'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2024', 'hcl': '#c0946f', 'iyr': '2013', 'hgt': '65in', 'byr': '1992', 'pid': '092712496', 'cid': '278', 'ecl': 'oth'}
|
||||
Checking {'ecl': 'brn', 'hcl': '#18171d', 'iyr': '2018', 'hgt': '151cm', 'byr': '1971', 'pid': '599220575', 'cid': '321', 'eyr': '2030'}
|
||||
Checking {'hcl': '#b6652a', 'iyr': '2016', 'byr': '1956', 'pid': '109381754', 'ecl': 'hzl', 'cid': '233'}
|
||||
Checking {'byr': '1992', 'cid': '278', 'ecl': 'oth', 'hgt': '65in', 'hcl': '#c0946f', 'iyr': '2013', 'pid': '092712496', 'eyr': '2024'}
|
||||
Checking {'hgt': '151cm', 'iyr': '2018', 'hcl': '#18171d', 'byr': '1971', 'pid': '599220575', 'cid': '321', 'eyr': '2030', 'ecl': 'brn'}
|
||||
Checking {'byr': '1956', 'iyr': '2016', 'hcl': '#b6652a', 'pid': '109381754', 'ecl': 'hzl', 'cid': '233'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#866857', 'iyr': '2015', 'hgt': '152cm', 'byr': '1988', 'pid': '274656754', 'ecl': 'amb', 'eyr': '2022'}
|
||||
Checking {'ecl': 'amb', 'hcl': '#733820', 'iyr': '2013', 'hgt': '186cm', 'byr': '1947', 'pid': '165847317', 'cid': '285', 'eyr': '2028'}
|
||||
Checking {'cid': '183', 'hcl': '#866857', 'pid': '601229952', 'hgt': '191cm', 'eyr': '2023', 'ecl': 'brn'}
|
||||
Checking {'iyr': '2015', 'byr': '1988', 'hcl': '#866857', 'ecl': 'amb', 'pid': '274656754', 'hgt': '152cm', 'eyr': '2022'}
|
||||
Checking {'eyr': '2028', 'ecl': 'amb', 'cid': '285', 'byr': '1947', 'hgt': '186cm', 'pid': '165847317', 'hcl': '#733820', 'iyr': '2013'}
|
||||
Checking {'hcl': '#866857', 'pid': '601229952', 'eyr': '2023', 'ecl': 'brn', 'hgt': '191cm', 'cid': '183'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#b50bab', 'iyr': '2018', 'hgt': '191cm', 'byr': '1936', 'pid': '422563929', 'eyr': '2025', 'ecl': 'oth'}
|
||||
Checking {'hcl': '#a97842', 'iyr': '2010', 'hgt': '181cm', 'byr': '1971', 'pid': '267796608', 'ecl': 'gry', 'eyr': '2025'}
|
||||
Checking {'cid': '301', 'hcl': '#0fd3b0', 'iyr': '2014', 'hgt': '173cm', 'pid': '606512017', 'byr': '1999', 'eyr': '2030', 'ecl': 'oth'}
|
||||
Checking {'ecl': 'grn', 'hcl': '#602927', 'iyr': '2018', 'hgt': '179cm', 'byr': '1937', 'pid': '148179917', 'cid': '277', 'eyr': '2029'}
|
||||
Checking {'hcl': '#7d3b0c', 'iyr': '2015', 'hgt': '162cm', 'byr': '1960', 'pid': '014246579', 'ecl': 'hzl', 'eyr': '2023'}
|
||||
Checking {'hcl': '#777876', 'iyr': '2011', 'hgt': '188cm', 'byr': '1955', 'pid': '988764375', 'ecl': 'blu', 'eyr': '2020'}
|
||||
Checking {'hcl': '#18171d', 'iyr': '2012', 'hgt': '173cm', 'pid': '524961020', 'byr': '1983', 'ecl': 'amb', 'eyr': '2028'}
|
||||
Checking {'hcl': '#efcc98', 'iyr': '2019', 'hgt': '153cm', 'pid': '127759635', 'byr': '1932', 'ecl': 'hzl', 'eyr': '2020'}
|
||||
Checking {'hcl': '#c0946f', 'iyr': '2013', 'pid': '421725637', 'byr': '1971', 'eyr': '2025', 'ecl': 'gry'}
|
||||
Checking {'hgt': '191cm', 'iyr': '2018', 'hcl': '#b50bab', 'byr': '1936', 'eyr': '2025', 'pid': '422563929', 'ecl': 'oth'}
|
||||
Checking {'ecl': 'gry', 'eyr': '2025', 'hgt': '181cm', 'hcl': '#a97842', 'byr': '1971', 'iyr': '2010', 'pid': '267796608'}
|
||||
Checking {'hcl': '#0fd3b0', 'eyr': '2030', 'iyr': '2014', 'ecl': 'oth', 'pid': '606512017', 'hgt': '173cm', 'cid': '301', 'byr': '1999'}
|
||||
Checking {'byr': '1937', 'cid': '277', 'pid': '148179917', 'hgt': '179cm', 'hcl': '#602927', 'iyr': '2018', 'eyr': '2029', 'ecl': 'grn'}
|
||||
Checking {'hcl': '#7d3b0c', 'byr': '1960', 'ecl': 'hzl', 'hgt': '162cm', 'iyr': '2015', 'pid': '014246579', 'eyr': '2023'}
|
||||
Checking {'ecl': 'blu', 'eyr': '2020', 'iyr': '2011', 'byr': '1955', 'hcl': '#777876', 'hgt': '188cm', 'pid': '988764375'}
|
||||
Checking {'iyr': '2012', 'ecl': 'amb', 'hcl': '#18171d', 'pid': '524961020', 'byr': '1983', 'hgt': '173cm', 'eyr': '2028'}
|
||||
Checking {'hgt': '153cm', 'hcl': '#efcc98', 'pid': '127759635', 'iyr': '2019', 'byr': '1932', 'ecl': 'hzl', 'eyr': '2020'}
|
||||
Checking {'eyr': '2025', 'pid': '421725637', 'ecl': 'gry', 'iyr': '2013', 'hcl': '#c0946f', 'byr': '1971'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#866857', 'iyr': '2015', 'hgt': '163cm', 'pid': '654033544', 'byr': '1923', 'cid': '176', 'ecl': 'brn'}
|
||||
Checking {'iyr': '2015', 'pid': '654033544', 'cid': '176', 'hgt': '163cm', 'byr': '1923', 'ecl': 'brn', 'hcl': '#866857'}
|
||||
Missing expected value
|
||||
Checking {'cid': '128', 'hcl': '#623a2f', 'iyr': '2007', 'hgt': '76cm', 'byr': '2013', 'pid': '122621229', 'ecl': '#5cd4a8', 'eyr': '2035'}
|
||||
Checking {'hcl': '#623a2f', 'byr': '2013', 'hgt': '76cm', 'ecl': '#5cd4a8', 'iyr': '2007', 'eyr': '2035', 'cid': '128', 'pid': '122621229'}
|
||||
Bad birth year
|
||||
Checking {'hcl': '#927794', 'iyr': '2019', 'hgt': '158cm', 'byr': '1964', 'pid': '269737193', 'ecl': 'oth', 'eyr': '2025'}
|
||||
Checking {'ecl': 'blu', 'hcl': '#341e13', 'iyr': '2014', 'hgt': '174cm', 'byr': '1949', 'pid': '120077363', 'eyr': '2026', 'cid': '181'}
|
||||
Checking {'ecl': 'oth', 'hcl': 'z', 'iyr': '2011', 'hgt': '151cm', 'pid': '638178037', 'byr': '1920', 'cid': '161', 'eyr': '2024'}
|
||||
Checking {'hcl': '#927794', 'iyr': '2019', 'byr': '1964', 'hgt': '158cm', 'ecl': 'oth', 'pid': '269737193', 'eyr': '2025'}
|
||||
Checking {'iyr': '2014', 'cid': '181', 'ecl': 'blu', 'byr': '1949', 'hcl': '#341e13', 'eyr': '2026', 'pid': '120077363', 'hgt': '174cm'}
|
||||
Checking {'cid': '161', 'eyr': '2024', 'hcl': 'z', 'pid': '638178037', 'hgt': '151cm', 'byr': '1920', 'ecl': 'oth', 'iyr': '2011'}
|
||||
bad hair color
|
||||
Checking {'eyr': '2023', 'hcl': '#a97842', 'iyr': '2014', 'hgt': '161cm', 'byr': '1977', 'pid': '177001463', 'cid': '79', 'ecl': 'brn'}
|
||||
Checking {'hcl': '#888785', 'iyr': '2010', 'hgt': '183cm', 'byr': '1938', 'pid': '302413712', 'eyr': '1967', 'ecl': 'grn'}
|
||||
Checking {'ecl': 'brn', 'eyr': '2023', 'hgt': '161cm', 'hcl': '#a97842', 'byr': '1977', 'cid': '79', 'pid': '177001463', 'iyr': '2014'}
|
||||
Checking {'byr': '1938', 'eyr': '1967', 'ecl': 'grn', 'pid': '302413712', 'hcl': '#888785', 'hgt': '183cm', 'iyr': '2010'}
|
||||
Bad expire year
|
||||
Checking {'hcl': '#c0946f', 'iyr': '2015', 'hgt': '164cm', 'byr': '1955', 'pid': '772380994', 'eyr': '2025', 'ecl': 'amb'}
|
||||
Checking {'cid': '161', 'hcl': '#602927', 'iyr': '2019', 'hgt': '171cm', 'byr': '1924', 'ecl': 'amb', 'eyr': '2021'}
|
||||
Checking {'hgt': '164cm', 'byr': '1955', 'pid': '772380994', 'iyr': '2015', 'hcl': '#c0946f', 'eyr': '2025', 'ecl': 'amb'}
|
||||
Checking {'hcl': '#602927', 'eyr': '2021', 'byr': '1924', 'hgt': '171cm', 'cid': '161', 'ecl': 'amb', 'iyr': '2019'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '7d1404', 'iyr': '2027', 'hgt': '119', 'pid': '143311761', 'byr': '1939', 'eyr': '1957', 'ecl': '#de1d21'}
|
||||
Checking {'hgt': '119', 'hcl': '7d1404', 'eyr': '1957', 'pid': '143311761', 'iyr': '2027', 'byr': '1939', 'ecl': '#de1d21'}
|
||||
Bad issue year
|
||||
Checking {'hcl': '#ceb3a1', 'iyr': '2015', 'hgt': '182cm', 'pid': '136552613', 'byr': '1992', 'ecl': 'blu', 'cid': '205'}
|
||||
Checking {'hgt': '182cm', 'iyr': '2015', 'ecl': 'blu', 'cid': '205', 'pid': '136552613', 'hcl': '#ceb3a1', 'byr': '1992'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2034', 'hcl': 'z', 'iyr': '2013', 'hgt': '172cm', 'byr': '1998', 'pid': '#ec3c3a', 'ecl': 'blu', 'cid': '54'}
|
||||
Checking {'ecl': 'blu', 'iyr': '2013', 'cid': '54', 'byr': '1998', 'hcl': 'z', 'hgt': '172cm', 'eyr': '2034', 'pid': '#ec3c3a'}
|
||||
Bad expire year
|
||||
Checking {'hcl': '#623a2f', 'iyr': '2012', 'byr': '1975', 'pid': '358585328', 'ecl': 'blu', 'eyr': '2025'}
|
||||
Checking {'byr': '1975', 'ecl': 'blu', 'eyr': '2025', 'hcl': '#623a2f', 'pid': '358585328', 'iyr': '2012'}
|
||||
Missing expected value
|
||||
Checking {'eyr': '2024', 'hcl': '#18171d', 'iyr': '2020', 'hgt': '190cm', 'pid': '282306278', 'byr': '1958', 'ecl': 'grn', 'cid': '276'}
|
||||
Checking {'hcl': '#6b5442', 'iyr': '2017', 'hgt': '177cm', 'byr': '1955', 'pid': '111002386', 'eyr': '2028', 'ecl': 'grn'}
|
||||
Checking {'cid': '109', 'hcl': '#866857', 'iyr': '2018', 'hgt': '169cm', 'pid': '694088201', 'byr': '1957', 'eyr': '2026', 'ecl': 'amb'}
|
||||
Checking {'hcl': '#6b5442', 'iyr': '2013', 'hgt': '171cm', 'byr': '1965', 'pid': '268169550', 'ecl': 'blu', 'eyr': '2021'}
|
||||
Checking {'cid': '173', 'hcl': '#a97842', 'iyr': '2010', 'hgt': '191cm', 'pid': '803092066', 'byr': '1956', 'eyr': '2023', 'ecl': 'grn'}
|
||||
Checking {'cid': '181', 'hcl': '#b6652a', 'iyr': '2012', 'hgt': '190cm', 'byr': '1991', 'pid': '946620993', 'eyr': '2024', 'ecl': 'gry'}
|
||||
Checking {'ecl': 'oth', 'hcl': '#cfa07d', 'iyr': '2019', 'hgt': '175cm', 'pid': '062548271', 'cid': '75', 'eyr': '2022'}
|
||||
Checking {'pid': '282306278', 'byr': '1958', 'ecl': 'grn', 'hgt': '190cm', 'iyr': '2020', 'hcl': '#18171d', 'cid': '276', 'eyr': '2024'}
|
||||
Checking {'byr': '1955', 'eyr': '2028', 'iyr': '2017', 'hgt': '177cm', 'ecl': 'grn', 'pid': '111002386', 'hcl': '#6b5442'}
|
||||
Checking {'eyr': '2026', 'pid': '694088201', 'hcl': '#866857', 'hgt': '169cm', 'byr': '1957', 'ecl': 'amb', 'iyr': '2018', 'cid': '109'}
|
||||
Checking {'hgt': '171cm', 'ecl': 'blu', 'iyr': '2013', 'eyr': '2021', 'hcl': '#6b5442', 'byr': '1965', 'pid': '268169550'}
|
||||
Checking {'pid': '803092066', 'eyr': '2023', 'iyr': '2010', 'hcl': '#a97842', 'ecl': 'grn', 'byr': '1956', 'hgt': '191cm', 'cid': '173'}
|
||||
Checking {'eyr': '2024', 'iyr': '2012', 'byr': '1991', 'ecl': 'gry', 'pid': '946620993', 'hgt': '190cm', 'hcl': '#b6652a', 'cid': '181'}
|
||||
Checking {'iyr': '2019', 'hcl': '#cfa07d', 'cid': '75', 'hgt': '175cm', 'eyr': '2022', 'pid': '062548271', 'ecl': 'oth'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#888785', 'iyr': '2014', 'byr': '1956', 'pid': '860561420', 'hgt': '176cm', 'cid': '262'}
|
||||
Checking {'cid': '262', 'byr': '1956', 'iyr': '2014', 'pid': '860561420', 'hcl': '#888785', 'hgt': '176cm'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#efcc98', 'iyr': '2013', 'hgt': '188cm', 'pid': '828180303', 'byr': '1932', 'ecl': 'gry', 'eyr': '2028'}
|
||||
Checking {'ecl': 'brn', 'hcl': '#341e13', 'iyr': '2012', 'hgt': '150cm', 'byr': '1992', 'pid': '644391775', 'cid': '292', 'eyr': '2029'}
|
||||
Checking {'hcl': '#ceb3a1', 'iyr': '2013', 'hgt': '182cm', 'byr': '1982', 'pid': '625704144', 'ecl': 'grn', 'eyr': '2026'}
|
||||
Checking {'hcl': '#812218', 'iyr': '2013', 'hgt': '150cm', 'byr': '1926', 'pid': '610910806', 'ecl': 'brn', 'eyr': '2025'}
|
||||
Checking {'hcl': '#623a2f', 'iyr': '2017', 'hgt': '61in', 'byr': '1926', 'pid': '347974562', 'eyr': '2020', 'ecl': 'oth'}
|
||||
Checking {'hcl': '#a97842', 'iyr': '2014', 'hgt': '185cm', 'byr': '1940', 'pid': '123961293', 'eyr': '2023', 'ecl': 'blu'}
|
||||
Checking {'hcl': '#692e6c', 'iyr': '2011', 'hgt': '172cm', 'byr': '1984', 'pid': '342962046', 'eyr': '2020', 'ecl': 'grn'}
|
||||
Checking {'eyr': '2023', 'hcl': '#b08932', 'iyr': '2019', 'hgt': '193cm', 'pid': '343331979', 'byr': '1985', 'ecl': 'blu', 'cid': '269'}
|
||||
Checking {'hcl': '#fffffd', 'iyr': '2011', 'pid': '483091240', 'byr': '1988', 'ecl': 'blu', 'eyr': '2022'}
|
||||
Checking {'hcl': '#efcc98', 'hgt': '188cm', 'pid': '828180303', 'iyr': '2013', 'byr': '1932', 'ecl': 'gry', 'eyr': '2028'}
|
||||
Checking {'eyr': '2029', 'hcl': '#341e13', 'byr': '1992', 'ecl': 'brn', 'iyr': '2012', 'cid': '292', 'pid': '644391775', 'hgt': '150cm'}
|
||||
Checking {'ecl': 'grn', 'hgt': '182cm', 'eyr': '2026', 'hcl': '#ceb3a1', 'byr': '1982', 'pid': '625704144', 'iyr': '2013'}
|
||||
Checking {'byr': '1926', 'iyr': '2013', 'ecl': 'brn', 'hcl': '#812218', 'eyr': '2025', 'hgt': '150cm', 'pid': '610910806'}
|
||||
Checking {'hgt': '61in', 'byr': '1926', 'iyr': '2017', 'eyr': '2020', 'ecl': 'oth', 'hcl': '#623a2f', 'pid': '347974562'}
|
||||
Checking {'hgt': '185cm', 'eyr': '2023', 'ecl': 'blu', 'byr': '1940', 'pid': '123961293', 'iyr': '2014', 'hcl': '#a97842'}
|
||||
Checking {'iyr': '2011', 'byr': '1984', 'hgt': '172cm', 'eyr': '2020', 'hcl': '#692e6c', 'ecl': 'grn', 'pid': '342962046'}
|
||||
Checking {'ecl': 'blu', 'hcl': '#b08932', 'pid': '343331979', 'iyr': '2019', 'hgt': '193cm', 'byr': '1985', 'cid': '269', 'eyr': '2023'}
|
||||
Checking {'hcl': '#fffffd', 'ecl': 'blu', 'pid': '483091240', 'iyr': '2011', 'eyr': '2022', 'byr': '1988'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#ceb3a1', 'iyr': '2019', 'hgt': '177cm', 'pid': '516533115', 'byr': '1922', 'cid': '294', 'ecl': 'amb'}
|
||||
Checking {'iyr': '2019', 'hgt': '177cm', 'pid': '516533115', 'cid': '294', 'ecl': 'amb', 'hcl': '#ceb3a1', 'byr': '1922'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '193cm', 'byr': '1965', 'pid': '931305875', 'eyr': '2023', 'ecl': 'grn'}
|
||||
Checking {'cid': '209', 'hcl': '#fffffd', 'iyr': '2019', 'hgt': '164cm', 'byr': '1944', 'pid': '141532765', 'ecl': 'hzl', 'eyr': '2029'}
|
||||
Checking {'hcl': '#ceb3a1', 'iyr': '2013', 'hgt': '189cm', 'pid': '604140631', 'byr': '1935', 'ecl': 'brn', 'eyr': '2022'}
|
||||
Checking {'eyr': '2027', 'hcl': '#888785', 'iyr': '2020', 'hgt': '152cm', 'byr': '1959', 'pid': '849438430', 'ecl': 'amb', 'cid': '287'}
|
||||
Checking {'hcl': '#623a2f', 'iyr': '2018', 'hgt': '167cm', 'byr': '1988', 'pid': '470443459', 'eyr': '2029', 'ecl': 'brn'}
|
||||
Checking {'eyr': '2021', 'hcl': '#341e13', 'iyr': '2012', 'hgt': '175cm', 'byr': '2027', 'pid': '271833606', 'ecl': 'hzl', 'cid': '276'}
|
||||
Checking {'byr': '1965', 'eyr': '2023', 'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '193cm', 'ecl': 'grn', 'pid': '931305875'}
|
||||
Checking {'ecl': 'hzl', 'byr': '1944', 'hgt': '164cm', 'hcl': '#fffffd', 'iyr': '2019', 'eyr': '2029', 'pid': '141532765', 'cid': '209'}
|
||||
Checking {'iyr': '2013', 'hgt': '189cm', 'ecl': 'brn', 'pid': '604140631', 'eyr': '2022', 'hcl': '#ceb3a1', 'byr': '1935'}
|
||||
Checking {'ecl': 'amb', 'hcl': '#888785', 'byr': '1959', 'cid': '287', 'pid': '849438430', 'hgt': '152cm', 'eyr': '2027', 'iyr': '2020'}
|
||||
Checking {'byr': '1988', 'hcl': '#623a2f', 'eyr': '2029', 'ecl': 'brn', 'iyr': '2018', 'hgt': '167cm', 'pid': '470443459'}
|
||||
Checking {'cid': '276', 'hcl': '#341e13', 'eyr': '2021', 'iyr': '2012', 'ecl': 'hzl', 'hgt': '175cm', 'byr': '2027', 'pid': '271833606'}
|
||||
Bad birth year
|
||||
Checking {'hcl': '#623a2f', 'iyr': '2010', 'hgt': '164cm', 'pid': '970527839', 'byr': '1974', 'eyr': '2027', 'ecl': 'amb'}
|
||||
Checking {'hcl': '#c0946f', 'iyr': '2013', 'byr': '1932', 'pid': '104193512', 'eyr': '2020', 'ecl': 'grn'}
|
||||
Checking {'eyr': '2027', 'iyr': '2010', 'pid': '970527839', 'hgt': '164cm', 'byr': '1974', 'hcl': '#623a2f', 'ecl': 'amb'}
|
||||
Checking {'eyr': '2020', 'ecl': 'grn', 'byr': '1932', 'iyr': '2013', 'pid': '104193512', 'hcl': '#c0946f'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#623a2f', 'iyr': '2020', 'hgt': '65in', 'byr': '1982', 'pid': '570953460', 'eyr': '2030', 'ecl': 'blu'}
|
||||
Checking {'hcl': '#602927', 'iyr': '2019', 'hgt': '169cm', 'byr': '1922', 'pid': '803264417', 'eyr': '2020', 'ecl': 'grn'}
|
||||
Checking {'hcl': '#866857', 'iyr': '2017', 'hgt': '170cm', 'byr': '1963', 'pid': '762546796', 'ecl': 'amb', 'eyr': '2028'}
|
||||
Checking {'cid': '184', 'hcl': '#733820', 'iyr': '1980', 'hgt': '176cm', 'pid': '54291174', 'byr': '1974', 'ecl': 'gry', 'eyr': '2035'}
|
||||
Checking {'eyr': '2030', 'byr': '1982', 'hgt': '65in', 'ecl': 'blu', 'hcl': '#623a2f', 'pid': '570953460', 'iyr': '2020'}
|
||||
Checking {'eyr': '2020', 'byr': '1922', 'hcl': '#602927', 'pid': '803264417', 'iyr': '2019', 'ecl': 'grn', 'hgt': '169cm'}
|
||||
Checking {'ecl': 'amb', 'hcl': '#866857', 'byr': '1963', 'hgt': '170cm', 'eyr': '2028', 'pid': '762546796', 'iyr': '2017'}
|
||||
Checking {'eyr': '2035', 'pid': '54291174', 'cid': '184', 'iyr': '1980', 'hgt': '176cm', 'ecl': 'gry', 'hcl': '#733820', 'byr': '1974'}
|
||||
Bad issue year
|
||||
Checking {'eyr': '2028', 'hcl': '#c0946f', 'iyr': '2013', 'hgt': '63in', 'pid': '408646971', 'byr': '1951', 'cid': '84', 'ecl': 'amb'}
|
||||
Checking {'hcl': '#6b5442', 'iyr': '2013', 'hgt': '170cm', 'byr': '1994', 'pid': '348959147', 'eyr': '2021', 'ecl': 'amb'}
|
||||
Checking {'cid': '199', 'hcl': 'e7c520', 'iyr': '2017', 'hgt': '156cm', 'byr': '1957', 'pid': '890752588', 'ecl': 'hzl', 'eyr': '2025'}
|
||||
Checking {'iyr': '2013', 'hcl': '#c0946f', 'pid': '408646971', 'hgt': '63in', 'cid': '84', 'byr': '1951', 'ecl': 'amb', 'eyr': '2028'}
|
||||
Checking {'eyr': '2021', 'hcl': '#6b5442', 'byr': '1994', 'hgt': '170cm', 'ecl': 'amb', 'pid': '348959147', 'iyr': '2013'}
|
||||
Checking {'byr': '1957', 'ecl': 'hzl', 'hgt': '156cm', 'pid': '890752588', 'eyr': '2025', 'hcl': 'e7c520', 'cid': '199', 'iyr': '2017'}
|
||||
bad hair color
|
||||
Checking {'eyr': '2024', 'hcl': '#733820', 'iyr': '2016', 'hgt': '169cm', 'pid': '661114936', 'byr': '1928', 'ecl': 'hzl', 'cid': '180'}
|
||||
Checking {'hcl': '#6b5442', 'iyr': '2015', 'hgt': '179cm', 'byr': '1941', 'pid': '148063033', 'eyr': '2020', 'ecl': 'brn'}
|
||||
Checking {'hcl': '#cfa07d', 'iyr': '1935', 'hgt': '59cm', 'pid': '14292032', 'byr': '2020', 'eyr': '1956', 'ecl': '#c9bc33'}
|
||||
Checking {'hgt': '169cm', 'iyr': '2016', 'cid': '180', 'hcl': '#733820', 'eyr': '2024', 'ecl': 'hzl', 'pid': '661114936', 'byr': '1928'}
|
||||
Checking {'iyr': '2015', 'eyr': '2020', 'byr': '1941', 'hgt': '179cm', 'pid': '148063033', 'hcl': '#6b5442', 'ecl': 'brn'}
|
||||
Checking {'iyr': '1935', 'pid': '14292032', 'byr': '2020', 'eyr': '1956', 'ecl': '#c9bc33', 'hgt': '59cm', 'hcl': '#cfa07d'}
|
||||
Bad birth year
|
||||
Checking {'ecl': 'amb', 'hcl': '#733820', 'iyr': '2010', 'hgt': '165cm', 'pid': '312465756', 'byr': '1993', 'eyr': '2023', 'cid': '112'}
|
||||
Checking {'hcl': 'z', 'iyr': '1963', 'hgt': '111', 'byr': '1964', 'pid': '#f5628c', 'eyr': '2032', 'ecl': 'grt'}
|
||||
Checking {'hgt': '165cm', 'iyr': '2010', 'eyr': '2023', 'hcl': '#733820', 'pid': '312465756', 'cid': '112', 'byr': '1993', 'ecl': 'amb'}
|
||||
Checking {'eyr': '2032', 'ecl': 'grt', 'iyr': '1963', 'byr': '1964', 'pid': '#f5628c', 'hcl': 'z', 'hgt': '111'}
|
||||
Bad issue year
|
||||
Checking {'eyr': '2023', 'hcl': '#623a2f', 'iyr': '2012', 'hgt': '169cm', 'pid': '809080900', 'byr': '1979', 'cid': '291', 'ecl': 'oth'}
|
||||
Checking {'iyr': '2021', 'byr': '1967', 'pid': '2498700612', 'hgt': '59cm', 'eyr': '2033', 'ecl': 'gmt'}
|
||||
Checking {'hgt': '169cm', 'iyr': '2012', 'hcl': '#623a2f', 'cid': '291', 'ecl': 'oth', 'pid': '809080900', 'byr': '1979', 'eyr': '2023'}
|
||||
Checking {'iyr': '2021', 'eyr': '2033', 'ecl': 'gmt', 'hgt': '59cm', 'byr': '1967', 'pid': '2498700612'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#b6652a', 'iyr': '2013', 'byr': '1953', 'pid': '442586860', 'ecl': 'oth'}
|
||||
Checking {'byr': '1953', 'ecl': 'oth', 'iyr': '2013', 'hcl': '#b6652a', 'pid': '442586860'}
|
||||
Missing expected value
|
||||
Checking {'hcl': '#866857', 'iyr': '2017', 'hgt': '151cm', 'pid': '095687847', 'byr': '1967', 'eyr': '2022', 'ecl': 'oth'}
|
||||
Checking {'hcl': '#866857', 'iyr': '1930', 'hgt': '61cm', 'pid': '983640144', 'byr': '1991', 'ecl': 'hzl', 'eyr': '2024'}
|
||||
Checking {'pid': '095687847', 'eyr': '2022', 'hgt': '151cm', 'byr': '1967', 'iyr': '2017', 'ecl': 'oth', 'hcl': '#866857'}
|
||||
Checking {'hcl': '#866857', 'pid': '983640144', 'hgt': '61cm', 'ecl': 'hzl', 'byr': '1991', 'iyr': '1930', 'eyr': '2024'}
|
||||
Bad issue year
|
||||
Checking {'hcl': '#602927', 'iyr': '2013', 'hgt': '151cm', 'byr': '1992', 'pid': '812583062', 'ecl': 'oth', 'eyr': '2025'}
|
||||
Checking {'ecl': 'oth', 'hcl': '#602927', 'eyr': '2025', 'iyr': '2013', 'hgt': '151cm', 'byr': '1992', 'pid': '812583062'}
|
||||
count = 194
|
||||
|
@ -1,9 +1,9 @@
|
||||
I am a function.
|
||||
[42]
|
||||
{'return': <class 'list'>, 'a': <class 'int'>, 'b': <class 'float'>}
|
||||
{'return': None, 'anint': <class 'int'>, 'self': <class '__main__.Foo'>, 'adict': 'dict[str,object]'}
|
||||
{'a': <class 'int'>, 'b': <class 'float'>, 'return': <class 'list'>}
|
||||
{'self': None, 'anint': <class 'int'>, 'adict': 'dict[str,object]', 'return': None}
|
||||
I am a method taking a dict.
|
||||
None
|
||||
{'astr': <class 'str'>, 'abool': <class 'bool'>}
|
||||
{'abool': <class 'bool'>, 'astr': <class 'str'>}
|
||||
I return a Foo? Amazing!
|
||||
True
|
||||
|
@ -26,5 +26,5 @@ last(1,2,7,3)
|
||||
last(1,2,test="thing")
|
||||
try:
|
||||
last(1,2,'c','d',7,8,extra='foo')
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
|
@ -1,5 +1,5 @@
|
||||
Positionals: [1, 2, 3, 'a', 'b']
|
||||
Keywords: {'biz': 42, 'foo': 'bar'}
|
||||
Keywords: {'foo': 'bar', 'biz': 42}
|
||||
hi
|
||||
Positionals: []
|
||||
Keywords: {}
|
||||
|
@ -1,3 +1,3 @@
|
||||
[31mCall starts here.[0m
|
||||
a = 1 b = 1
|
||||
args = [2, 3] kwargs = {'stuff': 'things', 'foo': 'bar'}
|
||||
args = [2, 3] kwargs = {'foo': 'bar', 'stuff': 'things'}
|
||||
|
@ -1,4 +1,4 @@
|
||||
['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__repr__', '__setattr__', '__str__', 'longList', 'ofAttributes', 'onThatObject', 'thatWeWantToSet']
|
||||
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__new__', '__repr__', '__setattr__', '__str__', 'longList', 'ofAttributes', 'onThatObject', 'thatWeWantToSet']
|
||||
1
|
||||
2
|
||||
3
|
||||
|
@ -8,7 +8,7 @@ class Foo():
|
||||
# This doesn't work because amethod is unbound and needs an instance.
|
||||
try:
|
||||
Foo.amethod()
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
# This works
|
||||
Foo.amethod(Foo())
|
||||
|
19
test/testClassMethodSuper.krk
Normal file
19
test/testClassMethodSuper.krk
Normal file
@ -0,0 +1,19 @@
|
||||
class Foo():
|
||||
@classmethod
|
||||
def cm(cls):
|
||||
print(f"{cls=}")
|
||||
|
||||
class Bar(Foo):
|
||||
pass
|
||||
|
||||
class Baz(Foo):
|
||||
@classmethod
|
||||
def cm(cls):
|
||||
print("(Baz)")
|
||||
super().cm()
|
||||
|
||||
|
||||
Bar.cm()
|
||||
Bar().cm()
|
||||
Baz.cm()
|
||||
Baz().cm()
|
6
test/testClassMethodSuper.krk.expect
Normal file
6
test/testClassMethodSuper.krk.expect
Normal file
@ -0,0 +1,6 @@
|
||||
cls=<class '__main__.Bar'>
|
||||
cls=<class '__main__.Bar'>
|
||||
(Baz)
|
||||
cls=<class '__main__.Baz'>
|
||||
(Baz)
|
||||
cls=<class '__main__.Baz'>
|
@ -9,5 +9,5 @@ print("{a} {b} {c}".format(**{'a': 1, 'b': "apples", 'c': object}))
|
||||
|
||||
try:
|
||||
print("{a} {b} {c}".format(a=True,**{'a': 1, 'b': "apples", 'c': object}))
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
|
18
test/testDecoratedRecursiveFunction.krk
Normal file
18
test/testDecoratedRecursiveFunction.krk
Normal file
@ -0,0 +1,18 @@
|
||||
def decorate(func):
|
||||
def _inner(a):
|
||||
print('in')
|
||||
a = func(a)
|
||||
print('out')
|
||||
return a
|
||||
return _inner
|
||||
|
||||
def foo():
|
||||
@decorate
|
||||
def bar(a):
|
||||
if a <= 0:
|
||||
return 0
|
||||
return bar(a-1)
|
||||
|
||||
bar(2)
|
||||
|
||||
foo()
|
6
test/testDecoratedRecursiveFunction.krk.expect
Normal file
6
test/testDecoratedRecursiveFunction.krk.expect
Normal file
@ -0,0 +1,6 @@
|
||||
in
|
||||
in
|
||||
in
|
||||
out
|
||||
out
|
||||
out
|
@ -120,7 +120,7 @@ def aMethod(with_,args=None):
|
||||
|
||||
try:
|
||||
aMethod()
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
|
||||
aMethod("just the first")
|
||||
@ -128,11 +128,11 @@ aMethod("the first","and the second")
|
||||
aMethod(args="hello",with_="world")
|
||||
try:
|
||||
aMethod(foo="hello",with_="bar")
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg) # unrecognized keyword arg, from inner method
|
||||
|
||||
aMethod(*[1,2])
|
||||
try:
|
||||
aMethod(*[1,2,3])
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg) # too many arguments
|
||||
|
@ -20,7 +20,7 @@ del l[3]
|
||||
print(l) # [1, 3, 4]
|
||||
try:
|
||||
del l[3]
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg) # List index out of range
|
||||
|
||||
let o = object()
|
||||
@ -36,13 +36,13 @@ print(dir(o.foo.bar))
|
||||
print(o.foo.bar.qux)
|
||||
try:
|
||||
print(o.foo.bar.baz)
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg) # AttributeError
|
||||
del o.foo.bar
|
||||
print(dir(o.foo))
|
||||
try:
|
||||
print(o.foo.bar)
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg) # AttributeError
|
||||
del o.foo
|
||||
del o
|
||||
|
@ -7,10 +7,10 @@ False
|
||||
[1, 3, 4, 5]
|
||||
[1, 3, 4]
|
||||
list index out of range: 3
|
||||
['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__repr__', '__setattr__', '__str__', 'baz', 'qux']
|
||||
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__new__', '__repr__', '__setattr__', '__str__', 'baz', 'qux']
|
||||
42
|
||||
['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__repr__', '__setattr__', '__str__', 'qux']
|
||||
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__new__', '__repr__', '__setattr__', '__str__', 'qux']
|
||||
hi
|
||||
'object' object has no attribute 'baz'
|
||||
['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__repr__', '__setattr__', '__str__']
|
||||
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__new__', '__repr__', '__setattr__', '__str__']
|
||||
'object' object has no attribute 'bar'
|
||||
|
9
test/testElseWithNoExcept.krk
Normal file
9
test/testElseWithNoExcept.krk
Normal file
@ -0,0 +1,9 @@
|
||||
try:
|
||||
try:
|
||||
raise ValueError()
|
||||
else:
|
||||
print("oh no (else should not run)")
|
||||
finally:
|
||||
print('finally')
|
||||
except ValueError:
|
||||
print("value error caught in outer")
|
2
test/testElseWithNoExcept.krk.expect
Normal file
2
test/testElseWithNoExcept.krk.expect
Normal file
@ -0,0 +1,2 @@
|
||||
finally
|
||||
value error caught in outer
|
13
test/testExceptionElseFinally.krk
Normal file
13
test/testExceptionElseFinally.krk
Normal file
@ -0,0 +1,13 @@
|
||||
for i in range(3):
|
||||
try:
|
||||
print('hello world')
|
||||
if i == 1:
|
||||
break
|
||||
except ValueError:
|
||||
print('value error')
|
||||
else:
|
||||
print('no error')
|
||||
finally:
|
||||
print('and done')
|
||||
|
||||
print('finished')
|
6
test/testExceptionElseFinally.krk.expect
Normal file
6
test/testExceptionElseFinally.krk.expect
Normal file
@ -0,0 +1,6 @@
|
||||
hello world
|
||||
no error
|
||||
and done
|
||||
hello world
|
||||
and done
|
||||
finished
|
14
test/testExceptionOnExceptExpression.krk
Normal file
14
test/testExceptionOnExceptExpression.krk
Normal file
@ -0,0 +1,14 @@
|
||||
try:
|
||||
try:
|
||||
print('hello world')
|
||||
raise ValueError()
|
||||
except 1/0:
|
||||
print("oh no")
|
||||
except ValueError:
|
||||
print("value error")
|
||||
finally:
|
||||
print('this is the finally')
|
||||
except ZeroDivisionError:
|
||||
print('caught the zero div error')
|
||||
|
||||
print('done')
|
4
test/testExceptionOnExceptExpression.krk.expect
Normal file
4
test/testExceptionOnExceptExpression.krk.expect
Normal file
@ -0,0 +1,4 @@
|
||||
hello world
|
||||
this is the finally
|
||||
caught the zero div error
|
||||
done
|
@ -2,7 +2,7 @@ def doTheThing(excp):
|
||||
try:
|
||||
try:
|
||||
raise excp
|
||||
except (TypeError, ValueError):
|
||||
except (TypeError, ValueError) as exception:
|
||||
print("Caught a", repr(exception))
|
||||
for i in exception.traceback:
|
||||
let func, instr = i
|
||||
|
98
test/testExpressionUnderlining.krk
Normal file
98
test/testExpressionUnderlining.krk
Normal file
@ -0,0 +1,98 @@
|
||||
import dis
|
||||
import fileio
|
||||
|
||||
from collections import deque
|
||||
|
||||
def test_a():
|
||||
def bar():
|
||||
return "string" + 42
|
||||
def foo():
|
||||
return bar() * 4
|
||||
foo()
|
||||
|
||||
def test_b():
|
||||
let foo = {
|
||||
'bar': {
|
||||
'baz': None
|
||||
}
|
||||
}
|
||||
|
||||
print(foo['bar']['baz']['qux']['etc'])
|
||||
|
||||
def test_c():
|
||||
import os
|
||||
os.system(42)
|
||||
|
||||
def test_d():
|
||||
let a = object()
|
||||
a.name = '42'
|
||||
let b = None
|
||||
let c = object()
|
||||
c.name = '42'
|
||||
print(a.name, b.name, c.name)
|
||||
|
||||
def test_e():
|
||||
let a = 1
|
||||
let b = 2
|
||||
class Confabulator:
|
||||
def __add__(self,other):
|
||||
return NotImplemented
|
||||
let c = Confabulator()
|
||||
let d = 4
|
||||
|
||||
let x = (a + b) @ (c + d)
|
||||
|
||||
def test_f():
|
||||
class Thing:
|
||||
def __init__(self, required):
|
||||
pass
|
||||
def __eq__(self, other):
|
||||
raise ValueError("oh no")
|
||||
|
||||
Thing('a') == Thing()
|
||||
|
||||
def disrec(code, seen):
|
||||
let next = deque()
|
||||
next.append(code)
|
||||
while next:
|
||||
let co = next.popleft()
|
||||
seen.add(co)
|
||||
let offset = 0
|
||||
for inst,size,operand in dis.examine(co):
|
||||
let expr = dis.ip_to_expression(co, offset + size - 1)
|
||||
if expr is not None:
|
||||
let lineNo, start, midStart, midEnd, end = expr
|
||||
if co.__file__:
|
||||
let j = 1
|
||||
with fileio.open(co.__file__,'r') as f:
|
||||
let line = f.readlines()[lineNo-1].rstrip()
|
||||
let i = 0
|
||||
while i < len(line):
|
||||
if line[i] not in ' \t': break
|
||||
j++
|
||||
i++
|
||||
while i < len(line):
|
||||
print(line[i],end='')
|
||||
i++
|
||||
print()
|
||||
while j < start:
|
||||
print(' ',end='')
|
||||
j++
|
||||
while j < midStart:
|
||||
print('~',end='')
|
||||
j++
|
||||
while j < midEnd:
|
||||
print('^',end='')
|
||||
j++
|
||||
while j < end:
|
||||
print('~',end='')
|
||||
j++
|
||||
print()
|
||||
if isinstance(operand,codeobject) and operand not in seen:
|
||||
next.append(operand)
|
||||
offset += size
|
||||
|
||||
for func_name in dir():
|
||||
if func_name.startswith('test_'):
|
||||
disrec(globals()[func_name].__code__,set())
|
||||
|
54
test/testExpressionUnderlining.krk.expect
Normal file
54
test/testExpressionUnderlining.krk.expect
Normal file
@ -0,0 +1,54 @@
|
||||
foo()
|
||||
~~~^~
|
||||
return "string" + 42
|
||||
~~~~~~~~~^~~~
|
||||
return bar() * 4
|
||||
~~~^~
|
||||
return bar() * 4
|
||||
~~~~~~^~~
|
||||
print(foo['bar']['baz']['qux']['etc'])
|
||||
~~~^~~~~~~
|
||||
print(foo['bar']['baz']['qux']['etc'])
|
||||
~~~~~~~~~~^~~~~~~
|
||||
print(foo['bar']['baz']['qux']['etc'])
|
||||
~~~~~~~~~~~~~~~~~^~~~~~~
|
||||
print(foo['bar']['baz']['qux']['etc'])
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
|
||||
print(foo['bar']['baz']['qux']['etc'])
|
||||
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
os.system(42)
|
||||
~~^~~~~~~
|
||||
os.system(42)
|
||||
~~~~~~~~~^~~~
|
||||
let a = object()
|
||||
~~~~~~^~
|
||||
a.name = '42'
|
||||
~~^^^^~~~~~~~
|
||||
let c = object()
|
||||
~~~~~~^~
|
||||
c.name = '42'
|
||||
~~^^^^~~~~~~~
|
||||
print(a.name, b.name, c.name)
|
||||
~^~~~~
|
||||
print(a.name, b.name, c.name)
|
||||
~^~~~~
|
||||
print(a.name, b.name, c.name)
|
||||
~^~~~~
|
||||
print(a.name, b.name, c.name)
|
||||
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
let c = Confabulator()
|
||||
~~~~~~~~~~~~^~
|
||||
let x = (a + b) @ (c + d)
|
||||
~~^~~
|
||||
let x = (a + b) @ (c + d)
|
||||
~~^~~
|
||||
let x = (a + b) @ (c + d)
|
||||
~~~~~~~~^~~~~~~~~
|
||||
Thing('a') == Thing()
|
||||
~~~~~^~~~~
|
||||
Thing('a') == Thing()
|
||||
~~~~~^~
|
||||
Thing('a') == Thing()
|
||||
~~~~~~~~~~~^^~~~~~~~~
|
||||
raise ValueError("oh no")
|
||||
~~~~~~~~~~^~~~~~~~~
|
38
test/testFloatFormatting.krk
Normal file
38
test/testFloatFormatting.krk
Normal file
@ -0,0 +1,38 @@
|
||||
import math
|
||||
|
||||
def print_values(values):
|
||||
for v in values:
|
||||
# Avoiding doing just 'v' as we want this test to work in Python and Kuroko with identical results
|
||||
# and Python will try to reduce the number of digits to the minimum required for disambiguity, which
|
||||
# we don't currently support.
|
||||
print(v.__format__('.16g'),v.__format__('f'),v.__format__('e'),v.__format__('#.16g'),v.__format__('+.4g'))
|
||||
|
||||
print_values([
|
||||
float('75.5834073120020679681'),
|
||||
float('75.5834073120020679681e-7'),
|
||||
float('75.5834073120020679681e-24'),
|
||||
float('75.5834073120020679681e80'),
|
||||
float('75.5834073120020679681e300'),
|
||||
float('75.0'),
|
||||
float('0.005'),
|
||||
float('0.0005'),
|
||||
float('0.5'),
|
||||
float('0.01'),
|
||||
float('0.25'),
|
||||
float('0.25')/2,
|
||||
float('0.25')/4,
|
||||
float('0.25')/8,
|
||||
float('0.25')/16,
|
||||
float('0.25')/2048,
|
||||
float('0.25')/4096,
|
||||
float('10000000253263163212.0'),
|
||||
(10**60)/1,
|
||||
float('20000000000000000'),
|
||||
0.0,
|
||||
-0.0,
|
||||
math.inf,
|
||||
-math.inf,
|
||||
math.nan,
|
||||
-math.nan,
|
||||
float('123.45'),
|
||||
])
|
27
test/testFloatFormatting.krk.expect
Normal file
27
test/testFloatFormatting.krk.expect
Normal file
@ -0,0 +1,27 @@
|
||||
75.58340731200207 75.583407 7.558341e+01 75.58340731200207 +75.58
|
||||
7.558340731200207e-06 0.000008 7.558341e-06 7.558340731200207e-06 +7.558e-06
|
||||
7.558340731200207e-23 0.000000 7.558341e-23 7.558340731200207e-23 +7.558e-23
|
||||
7.558340731200207e+81 7558340731200206731762734930317738502291660148265284220384036778702184341124939776.000000 7.558341e+81 7.558340731200207e+81 +7.558e+81
|
||||
7.558340731200207e+301 75583407312002066768461022261315172287297487251874586478724757817960934981634094788769653163852924763443651501309652569997165035925379465760402739890567710612092775360309017524288996057690996811122123668937191051711752654751620072621666259734026943606049685516409713620071805443138455356168154210369536.000000 7.558341e+301 7.558340731200207e+301 +7.558e+301
|
||||
75 75.000000 7.500000e+01 75.00000000000000 +75
|
||||
0.005 0.005000 5.000000e-03 0.005000000000000000 +0.005
|
||||
0.0005 0.000500 5.000000e-04 0.0005000000000000000 +0.0005
|
||||
0.5 0.500000 5.000000e-01 0.5000000000000000 +0.5
|
||||
0.01 0.010000 1.000000e-02 0.01000000000000000 +0.01
|
||||
0.25 0.250000 2.500000e-01 0.2500000000000000 +0.25
|
||||
0.125 0.125000 1.250000e-01 0.1250000000000000 +0.125
|
||||
0.0625 0.062500 6.250000e-02 0.06250000000000000 +0.0625
|
||||
0.03125 0.031250 3.125000e-02 0.03125000000000000 +0.03125
|
||||
0.015625 0.015625 1.562500e-02 0.01562500000000000 +0.01562
|
||||
0.0001220703125 0.000122 1.220703e-04 0.0001220703125000000 +0.0001221
|
||||
6.103515625e-05 0.000061 6.103516e-05 6.103515625000000e-05 +6.104e-05
|
||||
1.000000025326316e+19 10000000253263163392.000000 1.000000e+19 1.000000025326316e+19 +1e+19
|
||||
9.999999999999999e+59 999999999999999949387135297074018866963645011013410073083904.000000 1.000000e+60 9.999999999999999e+59 +1e+60
|
||||
2e+16 20000000000000000.000000 2.000000e+16 2.000000000000000e+16 +2e+16
|
||||
0 0.000000 0.000000e+00 0.000000000000000 +0
|
||||
-0 -0.000000 -0.000000e+00 -0.000000000000000 -0
|
||||
inf inf inf inf +inf
|
||||
-inf -inf -inf -inf -inf
|
||||
nan nan nan nan +nan
|
||||
nan nan nan nan +nan
|
||||
123.45 123.450000 1.234500e+02 123.4500000000000 +123.5
|
@ -1,3 +1,3 @@
|
||||
['__class__', '__dir__', '__eq__', '__format__', '__func__', '__getattr__', '__hash__', '__init__', '__module__', '__qualname__', '__repr__', '__setattr__', '__str__', '_dict']
|
||||
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__getattr__', '__hash__', '__init__', '__init_subclass__', '__module__', '__new__', '__qualname__', '__repr__', '__setattr__', '__str__', '_dict']
|
||||
1
|
||||
['__class__', '__dir__', '__eq__', '__format__', '__func__', '__hash__', '__module__', '__qualname__', '__repr__', '__setattr__', '__str__', 'butts']
|
||||
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__module__', '__new__', '__qualname__', '__repr__', '__setattr__', '__str__', 'butts']
|
||||
|
@ -1,8 +1,8 @@
|
||||
1
|
||||
hello
|
||||
3
|
||||
foo
|
||||
1: 2
|
||||
1
|
||||
3
|
||||
hello: world
|
||||
3: 4
|
||||
foo: bar
|
||||
1: 2
|
||||
3: 4
|
||||
|
@ -4,7 +4,7 @@ class Bar(object):
|
||||
|
||||
try:
|
||||
let b = Bar()
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
|
||||
class Foo():
|
||||
@ -13,6 +13,6 @@ class Foo():
|
||||
|
||||
try:
|
||||
let f = Foo()
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
|
||||
|
@ -1,2 +0,0 @@
|
||||
'object' object has no attribute '__init__'
|
||||
'object' object has no attribute '__init__'
|
15
test/testInitSubclassHook.krk
Normal file
15
test/testInitSubclassHook.krk
Normal file
@ -0,0 +1,15 @@
|
||||
class Foo:
|
||||
def __init_subclass__(cls,**kwds):
|
||||
print('Foo subclass',cls,'with args',kwds)
|
||||
|
||||
class Bar(Foo):
|
||||
pass
|
||||
|
||||
class Baz(Foo,foo=42):
|
||||
pass
|
||||
|
||||
class Qux(Bar):
|
||||
pass
|
||||
|
||||
class Florp(Bar,abc=123):
|
||||
pass
|
4
test/testInitSubclassHook.krk.expect
Normal file
4
test/testInitSubclassHook.krk.expect
Normal file
@ -0,0 +1,4 @@
|
||||
Foo subclass <class '__main__.Bar'> with args {}
|
||||
Foo subclass <class '__main__.Baz'> with args {'foo': 42}
|
||||
Foo subclass <class '__main__.Qux'> with args {}
|
||||
Foo subclass <class '__main__.Florp'> with args {'abc': 123}
|
@ -7,10 +7,10 @@ if True:
|
||||
|
||||
try:
|
||||
let a, b = range(3)
|
||||
except:
|
||||
except as exception:
|
||||
print(repr(exception))
|
||||
|
||||
try:
|
||||
let a, b, c, d = range(3)
|
||||
except:
|
||||
except as exception:
|
||||
print(repr(exception))
|
||||
|
@ -1,2 +1,2 @@
|
||||
{'glossary': {'title': 'example glossary', 'GlossDiv': {'title': 'S', 'GlossList': {'GlossEntry': {'SortAs': 'SGML', 'Abbrev': 'ISO 8879:1986', 'Acronym': 'SGML', 'GlossTerm': 'Standard Generalized Markup Language', 'GlossSee': 'markup', 'ID': 'SGML', 'GlossDef': {'para': 'A meta-markup language, used to create markup languages such as DocBook.', 'GlossSeeAlso': ['GML', 'XML']}}}}}}
|
||||
{'web-app': {'taglib': {'taglib-uri': 'cofax.tld', 'taglib-location': '/WEB-INF/tlds/cofax.tld'}, 'servlet': [{'servlet-class': 'org.cofax.cds.CDSServlet', 'init-param': {'templateProcessorClass': 'org.cofax.WysiwygTemplate', 'cachePagesStore': 100, 'searchEngineListTemplate': 'forSearchEnginesList.htm', 'searchEngineFileTemplate': 'forSearchEngines.htm', 'cachePackageTagsStore': 200, 'dataStoreUser': 'sa', 'dataStoreInitConns': 10, 'configGlossary:installationAt': 'Philadelphia, PA', 'cachePagesTrack': 200, 'dataStoreLogFile': '/usr/local/tomcat/logs/datastore.log', 'templateOverridePath': '', 'redirectionClass': 'org.cofax.SqlRedirection', 'cachePackageTagsTrack': 200, 'useDataStore': True, 'maxUrlLength': 500, 'dataStorePassword': 'dataStoreTestQuery', 'defaultFileTemplate': 'articleTemplate.htm', 'defaultListTemplate': 'listTemplate.htm', 'dataStoreConnUsageLimit': 100, 'templatePath': 'templates', 'useJSP': False, 'configGlossary:poweredBy': 'Cofax', 'dataStoreClass': 'org.cofax.SqlDataStore', 'dataStoreName': 'cofax', 'cacheTemplatesRefresh': 15, 'dataStoreDriver': 'com.microsoft.jdbc.sqlserver.SQLServerDriver', 'cachePagesDirtyRead': 10, 'configGlossary:adminEmail': 'ksm@pobox.com', 'dataStoreTestQuery': "SET NOCOUNT ON;select test='test';", 'cacheTemplatesStore': 50, 'templateLoaderClass': 'org.cofax.FilesTemplateLoader', 'configGlossary:staticPath': '/content/static', 'searchEngineRobotsDb': 'WEB-INF/robots.db', 'cacheTemplatesTrack': 100, 'dataStoreLogLevel': 'debug', 'dataStoreUrl': 'jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon', 'cachePagesRefresh': 10, 'configGlossary:poweredByIcon': '/images/cofax.gif', 'dataStoreMaxConns': 100, 'jspFileTemplate': 'articleTemplate.jsp', 'cachePackageTagsRefresh': 60, 'jspListTemplate': 'listTemplate.jsp'}, 'servlet-name': 'cofaxCDS'}, {'servlet-class': 'org.cofax.cds.EmailServlet', 'init-param': {'mailHostOverride': 'mail2', 'mailHost': 'mail1'}, 'servlet-name': 'cofaxEmail'}, {'servlet-class': 'org.cofax.cds.AdminServlet', 'servlet-name': 'cofaxAdmin'}, {'servlet-class': 'org.cofax.cds.FileServlet', 'servlet-name': 'fileServlet'}, {'servlet-class': 'org.cofax.cms.CofaxToolsServlet', 'init-param': {'logMaxSize': '', 'log': 1, 'removeTemplateCache': '/content/admin/remove?cache=templates&id=', 'dataLogMaxSize': '', 'lookInContext': 1, 'adminGroupID': 4, 'removePageCache': '/content/admin/remove?cache=pages&id=', 'dataLogLocation': '/usr/local/tomcat/logs/dataLog.log', 'betaServer': True, 'fileTransferFolder': '/usr/local/tomcat/webapps/content/fileTransferFolder', 'logLocation': '/usr/local/tomcat/logs/CofaxTools.log', 'dataLog': 1, 'templatePath': 'toolstemplates/'}, 'servlet-name': 'cofaxTools'}], 'servlet-mapping': {'cofaxCDS': '/', 'fileServlet': '/static/*', 'cofaxEmail': '/cofaxutil/aemail/*', 'cofaxTools': '/tools/*', 'cofaxAdmin': '/admin/*'}}}
|
||||
{'glossary': {'title': 'example glossary', 'GlossDiv': {'title': 'S', 'GlossList': {'GlossEntry': {'ID': 'SGML', 'SortAs': 'SGML', 'GlossTerm': 'Standard Generalized Markup Language', 'Acronym': 'SGML', 'Abbrev': 'ISO 8879:1986', 'GlossDef': {'para': 'A meta-markup language, used to create markup languages such as DocBook.', 'GlossSeeAlso': ['GML', 'XML']}, 'GlossSee': 'markup'}}}}}
|
||||
{'web-app': {'servlet': [{'servlet-name': 'cofaxCDS', 'servlet-class': 'org.cofax.cds.CDSServlet', 'init-param': {'configGlossary:installationAt': 'Philadelphia, PA', 'configGlossary:adminEmail': 'ksm@pobox.com', 'configGlossary:poweredBy': 'Cofax', 'configGlossary:poweredByIcon': '/images/cofax.gif', 'configGlossary:staticPath': '/content/static', 'templateProcessorClass': 'org.cofax.WysiwygTemplate', 'templateLoaderClass': 'org.cofax.FilesTemplateLoader', 'templatePath': 'templates', 'templateOverridePath': '', 'defaultListTemplate': 'listTemplate.htm', 'defaultFileTemplate': 'articleTemplate.htm', 'useJSP': False, 'jspListTemplate': 'listTemplate.jsp', 'jspFileTemplate': 'articleTemplate.jsp', 'cachePackageTagsTrack': 200, 'cachePackageTagsStore': 200, 'cachePackageTagsRefresh': 60, 'cacheTemplatesTrack': 100, 'cacheTemplatesStore': 50, 'cacheTemplatesRefresh': 15, 'cachePagesTrack': 200, 'cachePagesStore': 100, 'cachePagesRefresh': 10, 'cachePagesDirtyRead': 10, 'searchEngineListTemplate': 'forSearchEnginesList.htm', 'searchEngineFileTemplate': 'forSearchEngines.htm', 'searchEngineRobotsDb': 'WEB-INF/robots.db', 'useDataStore': True, 'dataStoreClass': 'org.cofax.SqlDataStore', 'redirectionClass': 'org.cofax.SqlRedirection', 'dataStoreName': 'cofax', 'dataStoreDriver': 'com.microsoft.jdbc.sqlserver.SQLServerDriver', 'dataStoreUrl': 'jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon', 'dataStoreUser': 'sa', 'dataStorePassword': 'dataStoreTestQuery', 'dataStoreTestQuery': "SET NOCOUNT ON;select test='test';", 'dataStoreLogFile': '/usr/local/tomcat/logs/datastore.log', 'dataStoreInitConns': 10, 'dataStoreMaxConns': 100, 'dataStoreConnUsageLimit': 100, 'dataStoreLogLevel': 'debug', 'maxUrlLength': 500}}, {'servlet-name': 'cofaxEmail', 'servlet-class': 'org.cofax.cds.EmailServlet', 'init-param': {'mailHost': 'mail1', 'mailHostOverride': 'mail2'}}, {'servlet-name': 'cofaxAdmin', 'servlet-class': 'org.cofax.cds.AdminServlet'}, {'servlet-name': 'fileServlet', 'servlet-class': 'org.cofax.cds.FileServlet'}, {'servlet-name': 'cofaxTools', 'servlet-class': 'org.cofax.cms.CofaxToolsServlet', 'init-param': {'templatePath': 'toolstemplates/', 'log': 1, 'logLocation': '/usr/local/tomcat/logs/CofaxTools.log', 'logMaxSize': '', 'dataLog': 1, 'dataLogLocation': '/usr/local/tomcat/logs/dataLog.log', 'dataLogMaxSize': '', 'removePageCache': '/content/admin/remove?cache=pages&id=', 'removeTemplateCache': '/content/admin/remove?cache=templates&id=', 'fileTransferFolder': '/usr/local/tomcat/webapps/content/fileTransferFolder', 'lookInContext': 1, 'adminGroupID': 4, 'betaServer': True}}], 'servlet-mapping': {'cofaxCDS': '/', 'cofaxEmail': '/cofaxutil/aemail/*', 'cofaxAdmin': '/admin/*', 'fileServlet': '/static/*', 'cofaxTools': '/tools/*'}, 'taglib': {'taglib-uri': 'cofax.tld', 'taglib-location': '/WEB-INF/tlds/cofax.tld'}}}
|
||||
|
@ -9,22 +9,22 @@ function(1,2,keyword2=5)
|
||||
|
||||
try:
|
||||
function(1,keyword2=5)
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
|
||||
try:
|
||||
function(1,2,positional1=4)
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
|
||||
try:
|
||||
function(1,2,keyword2=None,keyword2=5)
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
|
||||
function(1,keyword2=4,positional2="abc")
|
||||
|
||||
try:
|
||||
function(1,keyword2=4,keyword1=5,positional1="nope")
|
||||
except:
|
||||
except as exception:
|
||||
print(exception.arg)
|
||||
|
13
test/testNestedExceptionInFinally.krk
Normal file
13
test/testNestedExceptionInFinally.krk
Normal file
@ -0,0 +1,13 @@
|
||||
try:
|
||||
try:
|
||||
print('try')
|
||||
raise ValueError()
|
||||
except 1/0:
|
||||
print('bad: except body')
|
||||
finally:
|
||||
print(inner_error)
|
||||
print('bad: after inner error')
|
||||
except BaseException as e:
|
||||
while e:
|
||||
print(repr(e))
|
||||
e = e.__context__
|
4
test/testNestedExceptionInFinally.krk.expect
Normal file
4
test/testNestedExceptionInFinally.krk.expect
Normal file
@ -0,0 +1,4 @@
|
||||
try
|
||||
NameError("Undefined variable 'inner_error'.")
|
||||
ZeroDivisionError('integer division by zero')
|
||||
ValueError()
|
14
test/testNonDataDescriptor.krk
Normal file
14
test/testNonDataDescriptor.krk
Normal file
@ -0,0 +1,14 @@
|
||||
class NonDataDescriptor:
|
||||
def __get__(self, obj, objtype=None):
|
||||
return 42
|
||||
|
||||
class Foo:
|
||||
a = NonDataDescriptor()
|
||||
|
||||
def test(F):
|
||||
print(F.a)
|
||||
F.a = 7
|
||||
print(F.a)
|
||||
|
||||
test(Foo())
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user