Compare commits

..

1 Commits

Author SHA1 Message Date
K. Lange
0e3a007452 Test uncolored output 2023-08-30 16:36:04 +09:00
110 changed files with 2277 additions and 5947 deletions

View File

@ -21,7 +21,7 @@ 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)
ifneq ($(shell tools/can-floor-without-libm.sh $(CC)),yes)
LDLIBS += -lm
endif
@ -84,17 +84,6 @@ 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:
@ -133,7 +122,6 @@ 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}

View File

@ -45,6 +45,8 @@ 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`.

65
modules/callgrind.krk Normal file
View File

@ -0,0 +1,65 @@
'''
@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')

28
modules/dis.krk Normal file
View File

@ -0,0 +1,28 @@
'''
@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())

View File

@ -1,104 +0,0 @@
'''
@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

View File

@ -107,7 +107,7 @@ KRK_Method(object,__hash__) {
}
KrkObj * obj = AS_OBJECT(self);
if (!(obj->flags & KRK_OBJ_FLAGS_VALID_HASH)) {
obj->hash = (uint32_t)((intptr_t)(obj) >> 3);
obj->hash = INTEGER_VAL((int)((intptr_t)self >> 3));
obj->flags |= KRK_OBJ_FLAGS_VALID_HASH;
}
return INTEGER_VAL(obj->hash);
@ -115,7 +115,7 @@ KRK_Method(object,__hash__) {
KRK_Method(object,__eq__) {
METHOD_TAKES_EXACTLY(1);
if (krk_valuesSame(argv[0],argv[1])) return BOOLEAN_VAL(1);
if (argv[0] == argv[1]) return BOOLEAN_VAL(1);
return NOTIMPL_VAL();
}
@ -233,7 +233,7 @@ KRK_StaticMethod(object,__init_subclass__) {
* all types should have a string representation available through
* those methods.
*/
KRK_Method(object,__repr__) {
KRK_Method(object,__str__) {
KrkClass * type = krk_getType(self);
KrkValue module = NONE_VAL();
@ -262,13 +262,6 @@ _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]);
@ -316,7 +309,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->used; ++i) {
for (size_t i = 0; i < globals->capacity; ++i) {
KrkTableEntry * entry = &globals->entries[i];
if (IS_KWARGS(entry->key)) continue;
krk_writeValueArray(AS_LIST(myList), entry->key);
@ -363,19 +356,19 @@ KRK_Function(chr) {
KRK_Function(hex) {
FUNCTION_TAKES_EXACTLY(1);
trySlowMethod(vm.specialMethodNames[METHOD_HEX]);
trySlowMethod(OBJECT_VAL(S("__hex__")));
return TYPE_ERROR(int,argv[0]);
}
KRK_Function(oct) {
FUNCTION_TAKES_EXACTLY(1);
trySlowMethod(vm.specialMethodNames[METHOD_OCT]);
trySlowMethod(OBJECT_VAL(S("__oct__")));
return TYPE_ERROR(int,argv[0]);
}
KRK_Function(bin) {
FUNCTION_TAKES_EXACTLY(1);
trySlowMethod(vm.specialMethodNames[METHOD_BIN]);
trySlowMethod(OBJECT_VAL(S("__bin__")));
return TYPE_ERROR(int,argv[0]);
}
@ -390,7 +383,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)->used; ++i) {
for (size_t i = 0; i < AS_DICT(iterable)->capacity; ++i) {
if (!IS_KWARGS(AS_DICT(iterable)->entries[i].key)) {
if (callback(context, &AS_DICT(iterable)->entries[i].key, 1)) return 1;
}
@ -684,18 +677,18 @@ 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__) {
KrkValue iterator;
METHOD_TAKES_EXACTLY(1);
KrkValue start = INTEGER_VAL(0);
if (!krk_parseArgs(".V|V", (const char*[]){"iterable","start"}, &iterator, &start)) return NONE_VAL();
if (hasKw) krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("start")), &start);
krk_attachNamedValue(&self->fields, "_counter", start);
/* Attach iterator */
KrkClass * type = krk_getType(iterator);
KrkClass * type = krk_getType(argv[1]);
if (!type->_iter) {
return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", iterator);
return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", argv[1]);
}
krk_push(iterator);
krk_push(argv[1]);
KrkValue asIter = krk_callDirect(type->_iter, 1);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
krk_attachNamedValue(&self->fields, "_iterator", asIter);
@ -757,11 +750,13 @@ static int _sum_callback(void * context, const KrkValue * values, size_t count)
}
KRK_Function(sum) {
KrkValue iterable;
FUNCTION_TAKES_AT_LEAST(1);
KrkValue base = INTEGER_VAL(0);
if (!krk_parseArgs("V|$V", (const char*[]){"iterable","start"}, &iterable, &base)) return NONE_VAL();
if (hasKw) {
krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("start")), &base);
}
struct SimpleContext context = { base };
if (krk_unpackIterable(iterable, &context, _sum_callback)) return NONE_VAL();
if (krk_unpackIterable(argv[0], &context, _sum_callback)) return NONE_VAL();
return context.base;
}
@ -816,81 +811,42 @@ KRK_Function(max) {
}
KRK_Function(print) {
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();
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;
}
/* 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();
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;
}
/* 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 (!argc) {
for (size_t j = 0; j < endLen; ++j) {
fputc(end[j], stdout);
}
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();
}
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);
}
} else {
fwrite(AS_CSTRING(printable), AS_STRING(printable)->length, 1, stdout);
krk_pop();
if (i + 1 < remArgc) fwrite(sep, sepLen, 1, stdout);
krk_printValue(stdout, printable);
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return NONE_VAL();
}
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();
@ -1267,7 +1223,7 @@ KRK_Function(abs) {
return FLOATING_VAL(i >= 0 ? i : -i);
#endif
} else {
trySlowMethod(vm.specialMethodNames[METHOD_ABS]);
trySlowMethod(OBJECT_VAL(S("__abs__")));
return krk_runtimeError(vm.exceptions->typeError, "bad operand type for 'abs()': '%T'", argv[0]);
}
}
@ -1297,7 +1253,7 @@ static void module_sweep(KrkInstance * inst) {
#ifndef KRK_STATIC_ONLY
struct KrkModule * module = (struct KrkModule*)inst;
if (module->libHandle) {
krk_dlClose(module->libHandle);
dlClose(module->libHandle);
}
#endif
}
@ -1444,7 +1400,6 @@ 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__);
@ -1452,6 +1407,7 @@ void _createAndBind_builtins(void) {
BIND_STATICMETHOD(object,__new__);
BIND_METHOD(object,__init__);
BIND_CLASSMETHOD(object,__init_subclass__);
krk_defineNative(&object->methods, "__repr__", FUNC_NAME(object,__str__));
krk_finalizeClass(object);
KRK_DOC(object,
"@brief Base class for all types.\n\n"
@ -1468,6 +1424,7 @@ 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.");
@ -1627,7 +1584,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',file=None,flush=False\n\n"
"@arguments *args,sep=' ',end='\\n'\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.");

View File

@ -13,7 +13,6 @@ void krk_initChunk(KrkChunk * chunk) {
chunk->linesCapacity = 0;
chunk->lines = NULL;
chunk->filename = NULL;
krk_initValueArray(&chunk->constants);
}
@ -21,8 +20,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 = KRK_GROW_CAPACITY(old);
chunk->lines = KRK_GROW_ARRAY(KrkLineMap, chunk->lines, old, chunk->linesCapacity);
chunk->linesCapacity = GROW_CAPACITY(old);
chunk->lines = GROW_ARRAY(KrkLineMap, chunk->lines, old, chunk->linesCapacity);
}
chunk->lines[chunk->linesCount] = (KrkLineMap){chunk->count, line};
chunk->linesCount++;
@ -31,8 +30,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 = KRK_GROW_CAPACITY(old);
chunk->code = KRK_GROW_ARRAY(uint8_t, chunk->code, old, chunk->capacity);
chunk->capacity = GROW_CAPACITY(old);
chunk->code = GROW_ARRAY(uint8_t, chunk->code, old, chunk->capacity);
}
chunk->code[chunk->count] = byte;
@ -41,8 +40,8 @@ void krk_writeChunk(KrkChunk * chunk, uint8_t byte, size_t line) {
}
void krk_freeChunk(KrkChunk * chunk) {
KRK_FREE_ARRAY(uint8_t, chunk->code, chunk->capacity);
KRK_FREE_ARRAY(KrkLineMap, chunk->lines, chunk->linesCapacity);
FREE_ARRAY(uint8_t, chunk->code, chunk->capacity);
FREE_ARRAY(KrkLineMap, chunk->lines, chunk->linesCapacity);
krk_freeValueArray(&chunk->constants);
krk_initChunk(chunk);
}
@ -73,29 +72,11 @@ size_t krk_writeConstant(KrkChunk * chunk, KrkValue value, size_t line) {
}
size_t krk_lineNumber(KrkChunk * chunk, size_t offset) {
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) {
for (size_t i = 0; i < chunk->linesCount; ++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 0;
}

View File

@ -259,7 +259,6 @@ typedef struct ChunkRecorder {
size_t count; /**< @brief Offset into the bytecode */
size_t lines; /**< @brief Offset into the line map */
size_t constants; /**< @brief Number of constants in the constants table */
size_t expressions;/**< @brief Number of expression mapping entries */
} ChunkRecorder;
/**
@ -337,18 +336,15 @@ _exit:
return writer;
}
#define codeobject_from_chunk_pointer(ptr) ((KrkCodeObject*)((char *)(ptr) - offsetof(KrkCodeObject, chunk)))
static ChunkRecorder recordChunk(KrkChunk * in) {
return (ChunkRecorder){in->count, in->linesCount, in->constants.count, codeobject_from_chunk_pointer(in)->expressionsCount};
return (ChunkRecorder){in->count, in->linesCount, in->constants.count};
}
static void rewindChunk(KrkChunk * out, ChunkRecorder from) {
out->count = from.count;
out->linesCount = from.lines;
out->constants.count = from.constants;
codeobject_from_chunk_pointer(out)->expressionsCount = from.expressions;
}
#undef codeobject_from_chunk_pointer
static size_t renameLocal(struct GlobalState * state, size_t ind, KrkToken name);
@ -362,7 +358,7 @@ static void initCompiler(struct GlobalState * state, Compiler * compiler, Functi
compiler->codeobject = krk_newCodeObject();
compiler->localCount = 0;
compiler->localsSpace = 8;
compiler->locals = KRK_GROW_ARRAY(Local,NULL,0,8);
compiler->locals = GROW_ARRAY(Local,NULL,0,8);
compiler->upvaluesSpace = 0;
compiler->upvalues = NULL;
compiler->breakCount = 0;
@ -576,25 +572,13 @@ static KrkCodeObject * endCompiler(struct GlobalState * state) {
function->localNames[i].deathday = currentChunk()->count;
}
}
function->localNames = KRK_GROW_ARRAY(KrkLocalEntry, function->localNames,
function->localNames = GROW_ARRAY(KrkLocalEntry, function->localNames, \
state->current->localNameCapacity, function->localNameCount); /* Shorten this down for runtime */
if (state->current->continueCount) { state->parser.previous = state->current->continues[0].token; error("continue without loop"); }
if (state->current->breakCount) { state->parser.previous = state->current->breaks[0].token; error("break without loop"); }
emitReturn(state);
/* Reduce the size of dynamic arrays to their fixed sizes. */
function->chunk.lines = KRK_GROW_ARRAY(KrkLineMap, function->chunk.lines,
function->chunk.linesCapacity, function->chunk.linesCount);
function->chunk.linesCapacity = function->chunk.linesCount;
function->chunk.code = KRK_GROW_ARRAY(uint8_t, function->chunk.code,
function->chunk.capacity, function->chunk.count);
function->chunk.capacity = function->chunk.count;
function->expressions = KRK_GROW_ARRAY(KrkExpressionsMap, function->expressions,
function->expressionsCapacity, function->expressionsCount);
function->expressionsCapacity = function->expressionsCount;
/* Attach contants for arguments */
for (int i = 0; i < function->potentialPositionals; ++i) {
if (i < state->current->unnamedArgs) {
@ -637,7 +621,7 @@ static KrkCodeObject * endCompiler(struct GlobalState * state) {
function->totalArguments = function->potentialPositionals + function->keywordArgs + !!(function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS);
#if !defined(KRK_NO_DISASSEMBLY) && !defined(KRK_DISABLE_DEBUG)
#ifndef KRK_NO_DISASSEMBLY
if ((krk_currentThread.flags & KRK_THREAD_ENABLE_DISASSEMBLY) && !state->parser.hadError) {
krk_disassembleCodeObject(stderr, function, function->name ? function->name->chars : "(module)");
}
@ -648,10 +632,10 @@ static KrkCodeObject * endCompiler(struct GlobalState * state) {
}
static void freeCompiler(Compiler * compiler) {
KRK_FREE_ARRAY(Local,compiler->locals, compiler->localsSpace);
KRK_FREE_ARRAY(Upvalue,compiler->upvalues, compiler->upvaluesSpace);
KRK_FREE_ARRAY(struct LoopExit,compiler->breaks, compiler->breakSpace);
KRK_FREE_ARRAY(struct LoopExit,compiler->continues, compiler->continueSpace);
FREE_ARRAY(Local,compiler->locals, compiler->localsSpace);
FREE_ARRAY(Upvalue,compiler->upvalues, compiler->upvaluesSpace);
FREE_ARRAY(struct LoopExit,compiler->breaks, compiler->breakSpace);
FREE_ARRAY(struct LoopExit,compiler->continues, compiler->continueSpace);
while (compiler->properties) {
void * tmp = compiler->properties;
@ -714,8 +698,8 @@ static ssize_t resolveLocal(struct GlobalState * state, Compiler * compiler, Krk
static size_t renameLocal(struct GlobalState * state, size_t ind, KrkToken name) {
if (state->current->codeobject->localNameCount + 1 > state->current->localNameCapacity) {
size_t old = state->current->localNameCapacity;
state->current->localNameCapacity = KRK_GROW_CAPACITY(old);
state->current->codeobject->localNames = KRK_GROW_ARRAY(KrkLocalEntry, state->current->codeobject->localNames, old, state->current->localNameCapacity);
state->current->localNameCapacity = GROW_CAPACITY(old);
state->current->codeobject->localNames = GROW_ARRAY(KrkLocalEntry, state->current->codeobject->localNames, old, state->current->localNameCapacity);
}
state->current->codeobject->localNames[state->current->codeobject->localNameCount].id = ind;
state->current->codeobject->localNames[state->current->codeobject->localNameCount].birthday = currentChunk()->count;
@ -727,8 +711,8 @@ static size_t renameLocal(struct GlobalState * state, size_t ind, KrkToken name)
static size_t addLocal(struct GlobalState * state, KrkToken name) {
if (state->current->localCount + 1 > state->current->localsSpace) {
size_t old = state->current->localsSpace;
state->current->localsSpace = KRK_GROW_CAPACITY(old);
state->current->locals = KRK_GROW_ARRAY(Local,state->current->locals,old,state->current->localsSpace);
state->current->localsSpace = GROW_CAPACITY(old);
state->current->locals = GROW_ARRAY(Local,state->current->locals,old,state->current->localsSpace);
}
size_t out = state->current->localCount;
Local * local = &state->current->locals[state->current->localCount++];
@ -800,10 +784,10 @@ static void number(struct GlobalState * state, int exprType, RewindState *rewind
invalidTarget(state, exprType, "literal");
for (size_t j = 0; j < state->parser.previous.length; ++j) {
if (start[j] == 'x' || start[j] == 'X') break;
if (start[j] == '.' || start[j] == 'e' || start[j] == 'E') {
if (state->parser.previous.start[j] == '.') {
#ifndef KRK_NO_FLOAT
emitConstant(krk_parse_float(start, state->parser.previous.length));
double value = strtod(start, NULL);
emitConstant(FLOATING_VAL(value));
#else
error("no float support");
#endif
@ -827,43 +811,9 @@ static int _emitJump(struct GlobalState * state, uint8_t opcode) {
}
#define emitJump(o) _emitJump(state,o)
/**
* @brief Emit over-long jump target.
*
* Our jump instructions take only two bytes as operands, as that typically suffices
* for storing the appropriate forward or backwards offset, without needing to waste
* lots of bytes for small jumps, or recalculate everything to expand a jump to
* fit a larger offset. If we *do* get a jump offset that is too big to fit in our
* available operand space, we replace the whole instruction with one that fetches
* the desired target, slowly, from a table attached to the codeobject, alongside
* the original instruction opcode.
*/
static void _emitOverlongJump(struct GlobalState * state, int offset, int jump) {
KrkCodeObject * co = state->current->codeobject;
size_t i = 0;
while (i < co->overlongJumpsCount && co->overlongJumps[i].instructionOffset != (uint32_t)offset) i++;
if (i == co->overlongJumpsCount) {
/* Not an existing overlong jump, need to make a new one. */
if (co->overlongJumpsCount + 1 > co->overlongJumpsCapacity) {
size_t old = co->overlongJumpsCapacity;
co->overlongJumpsCapacity = KRK_GROW_CAPACITY(old);
co->overlongJumps = KRK_GROW_ARRAY(KrkOverlongJump,co->overlongJumps,old,co->overlongJumpsCapacity);
}
co->overlongJumps[i].instructionOffset = offset;
co->overlongJumps[i].originalOpcode = currentChunk()->code[offset-1];
co->overlongJumpsCount++;
currentChunk()->code[offset-1] = OP_OVERLONG_JUMP;
}
/* Update jump target */
co->overlongJumps[i].intendedTarget = jump >> 16;
}
static void _patchJump(struct GlobalState * state, int offset) {
int jump = currentChunk()->count - offset - 2;
if (jump > 0xFFFF) {
_emitOverlongJump(state, offset, jump);
}
if (jump > 0xFFFF) error("Jump offset is too large for opcode.");
currentChunk()->code[offset] = (jump >> 8) & 0xFF;
currentChunk()->code[offset + 1] = (jump) & 0xFF;
@ -871,49 +821,10 @@ static void _patchJump(struct GlobalState * state, int offset) {
#define patchJump(o) _patchJump(state,o)
/**
* @brief Add expression debug information.
*
* This allows us to print tracebacks with underlined expressions,
* implementing Python's PEP 657. We store information on the
* left and right sides of binary expressions and the "main" token
* of the expression (the binary operator, usually).
*
* This should be called immediately after the relevant opcode is
* emitted. The mapping applies to only a single opcode, so it should
* be the one that is going to cause an exception to be raised - be
* particularly careful not emit this after an @c OP_NOT if it comes
* after a more relevant opcode.
*
* If the token mechanism here doesn't provide sufficient flexibility,
* artificial tokens can be created to set up the spans.
*/
static void writeExpressionLocation(KrkToken * before, KrkToken * after, KrkToken * current, struct GlobalState * state) {
#ifndef KRK_DISABLE_DEBUG
/* We can only support the display of underlines when the whole expression is on one line. */
if (after->linePtr != before->linePtr) return;
if (after->line != state->parser.previous.line) return;
/* For the sake of runtime storage, we only store this debug information
* when it fits within the first 256 characters of a line, so we can
* use uint8_ts to store these. */
if (before->col > 255 || current->col > 255 ||
(current->col + current->literalWidth) > 255 ||
(after->col + after->literalWidth) > 255) return;
krk_debug_addExpression(state->current->codeobject,
before->col, current->col,
current->col + current->literalWidth,
after->col + after->literalWidth);
#endif
}
static void compareChained(struct GlobalState * state, int inner, KrkToken * preceding) {
static void compareChained(struct GlobalState * state, int inner) {
KrkTokenType operatorType = state->parser.previous.type;
if (operatorType == TOKEN_NOT) consume(TOKEN_IN, "'in' must follow infix 'not'");
int invert = (operatorType == TOKEN_IS && match(TOKEN_NOT));
KrkToken this = state->parser.previous;
KrkToken next = state->parser.current;
ParseRule * rule = getRule(operatorType);
parsePrecedence(state, (Precedence)(rule->precedence + 1));
@ -924,28 +835,25 @@ static void compareChained(struct GlobalState * state, int inner, KrkToken * pre
}
switch (operatorType) {
case TOKEN_BANG_EQUAL: emitByte(OP_EQUAL); invert = 1; break;
case TOKEN_BANG_EQUAL: emitBytes(OP_EQUAL, OP_NOT); break;
case TOKEN_EQUAL_EQUAL: emitByte(OP_EQUAL); break;
case TOKEN_GREATER: emitByte(OP_GREATER); break;
case TOKEN_GREATER_EQUAL: emitByte(OP_GREATER_EQUAL); break;
case TOKEN_LESS: emitByte(OP_LESS); break;
case TOKEN_LESS_EQUAL: emitByte(OP_LESS_EQUAL); break;
case TOKEN_IS: emitByte(OP_IS); break;
case TOKEN_IS: emitByte(OP_IS); if (invert) emitByte(OP_NOT); break;
case TOKEN_IN: emitByte(OP_INVOKE_CONTAINS); break;
case TOKEN_NOT: emitByte(OP_INVOKE_CONTAINS); invert = 1; break;
case TOKEN_NOT: emitBytes(OP_INVOKE_CONTAINS, OP_NOT); break;
default: error("Invalid binary comparison operator?"); break;
}
writeExpressionLocation(preceding, &state->parser.previous, &this, state);
if (invert) emitByte(OP_NOT);
if (getRule(state->parser.current.type)->precedence == PREC_COMPARISON) {
size_t exitJump = emitJump(OP_JUMP_IF_FALSE_OR_POP);
advance();
compareChained(state, 1, &next);
compareChained(state, 1);
patchJump(exitJump);
if (getRule(state->parser.current.type)->precedence != PREC_COMPARISON) {
if (!inner) {
@ -959,14 +867,13 @@ static void compareChained(struct GlobalState * state, int inner, KrkToken * pre
}
static void compare(struct GlobalState * state, int exprType, RewindState *rewind) {
compareChained(state, 0, &rewind->oldParser.current);
compareChained(state, 0);
invalidTarget(state, exprType, "operator");
}
static void binary(struct GlobalState * state, int exprType, RewindState *rewind) {
KrkTokenType operatorType = state->parser.previous.type;
ParseRule * rule = getRule(operatorType);
KrkToken this = state->parser.previous;
parsePrecedence(state, (Precedence)(rule->precedence + (rule->precedence != PREC_EXPONENT)));
invalidTarget(state, exprType, "operator");
@ -988,7 +895,6 @@ static void binary(struct GlobalState * state, int exprType, RewindState *rewind
case TOKEN_AT: emitByte(OP_MATMUL); break;
default: return;
}
writeExpressionLocation(&rewind->oldParser.current, &state->parser.previous, &this, state);
}
static int matchAssignment(struct GlobalState * state) {
@ -1025,7 +931,6 @@ static int invalidTarget(struct GlobalState * state, int exprType, const char *
static void assignmentValue(struct GlobalState * state) {
KrkTokenType type = state->parser.previous.type;
KrkToken left = state->parser.previous;
if (type == TOKEN_PLUS_PLUS || type == TOKEN_MINUS_MINUS) {
emitConstant(INTEGER_VAL(1));
} else {
@ -1054,7 +959,6 @@ static void assignmentValue(struct GlobalState * state) {
error("Unexpected operand in assignment");
break;
}
writeExpressionLocation(&left,&state->parser.previous,&left,state);
}
static void expression(struct GlobalState * state) {
@ -1097,9 +1001,6 @@ static void sliceExpression(struct GlobalState * state) {
static void getitem(struct GlobalState * state, int exprType, RewindState *rewind) {
KrkToken *left = &rewind->oldParser.current;
KrkToken this = state->parser.previous;
sliceExpression(state);
if (match(TOKEN_COMMA)) {
@ -1118,7 +1019,6 @@ static void getitem(struct GlobalState * state, int exprType, RewindState *rewin
if (matchComplexEnd(state)) {
EMIT_OPERAND_OP(OP_DUP, 2);
emitByte(OP_INVOKE_SETTER);
writeExpressionLocation(left,&state->parser.current,&this,state);
emitByte(OP_POP);
return;
}
@ -1127,21 +1027,16 @@ static void getitem(struct GlobalState * state, int exprType, RewindState *rewin
if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
parsePrecedence(state, PREC_ASSIGNMENT);
emitByte(OP_INVOKE_SETTER);
writeExpressionLocation(left,&state->parser.previous,&this,state);
} else if (exprType == EXPR_CAN_ASSIGN && matchAssignment(state)) {
emitBytes(OP_DUP, 1); /* o e o */
emitBytes(OP_DUP, 1); /* o e o e */
emitByte(OP_INVOKE_GETTER); /* o e v */
writeExpressionLocation(left,&state->parser.previous,&this,state);
assignmentValue(state); /* o e v a */
emitByte(OP_INVOKE_SETTER); /* r */
writeExpressionLocation(left,&state->parser.previous,&this,state);
} else if (exprType == EXPR_DEL_TARGET && checkEndOfDel(state)) {
emitByte(OP_INVOKE_DELETE);
writeExpressionLocation(left,&state->parser.previous,&this,state);
} else {
emitByte(OP_INVOKE_GETTER);
writeExpressionLocation(left,&state->parser.previous,&this,state);
}
}
@ -1149,13 +1044,13 @@ static void attributeUnpack(struct GlobalState * state, int exprType) {
startEatingWhitespace();
size_t argCount = 0;
size_t argSpace = 1;
ssize_t * args = KRK_GROW_ARRAY(ssize_t,NULL,0,1);
ssize_t * args = GROW_ARRAY(ssize_t,NULL,0,1);
do {
if (argSpace < argCount + 1) {
size_t old = argSpace;
argSpace = KRK_GROW_CAPACITY(old);
args = KRK_GROW_ARRAY(ssize_t,args,old,argSpace);
argSpace = GROW_CAPACITY(old);
args = GROW_ARRAY(ssize_t,args,old,argSpace);
}
consume(TOKEN_IDENTIFIER, "Expected attribute name");
size_t ind = identifierConstant(state, &state->parser.previous);
@ -1207,7 +1102,7 @@ static void attributeUnpack(struct GlobalState * state, int exprType) {
}
_dotDone:
KRK_FREE_ARRAY(ssize_t,args,argSpace);
FREE_ARRAY(ssize_t,args,argSpace);
return;
}
@ -1216,15 +1111,12 @@ static void dot(struct GlobalState * state, int exprType, RewindState *rewind) {
attributeUnpack(state, exprType);
return;
}
KrkToken name = state->parser.current;
KrkToken this = state->parser.previous;
consume(TOKEN_IDENTIFIER, "Expected property name");
size_t ind = identifierConstant(state, &state->parser.previous);
if (exprType == EXPR_ASSIGN_TARGET) {
if (matchComplexEnd(state)) {
EMIT_OPERAND_OP(OP_DUP, 1);
EMIT_OPERAND_OP(OP_SET_PROPERTY, ind);
writeExpressionLocation(&rewind->oldParser.current, &state->parser.previous, &name, state);
emitByte(OP_POP);
return;
}
@ -1233,24 +1125,18 @@ static void dot(struct GlobalState * state, int exprType, RewindState *rewind) {
if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
parsePrecedence(state, PREC_ASSIGNMENT);
EMIT_OPERAND_OP(OP_SET_PROPERTY, ind);
writeExpressionLocation(&rewind->oldParser.current, &state->parser.previous, &name, state);
} else if (exprType == EXPR_CAN_ASSIGN && matchAssignment(state)) {
emitBytes(OP_DUP, 0); /* Duplicate the object */
EMIT_OPERAND_OP(OP_GET_PROPERTY, ind);
writeExpressionLocation(&rewind->oldParser.current, &name, &this, state);
assignmentValue(state);
EMIT_OPERAND_OP(OP_SET_PROPERTY, ind);
writeExpressionLocation(&rewind->oldParser.current, &state->parser.previous, &name, state);
} else if (exprType == EXPR_DEL_TARGET && checkEndOfDel(state)) {
EMIT_OPERAND_OP(OP_DEL_PROPERTY, ind);
writeExpressionLocation(&rewind->oldParser.current, &name, &this, state);
} else if (match(TOKEN_LEFT_PAREN)) {
EMIT_OPERAND_OP(OP_GET_METHOD, ind);
writeExpressionLocation(&rewind->oldParser.current, &name, &this, state);
call(state, EXPR_METHOD_CALL, rewind);
call(state, EXPR_METHOD_CALL,NULL);
} else {
EMIT_OPERAND_OP(OP_GET_PROPERTY, ind);
writeExpressionLocation(&rewind->oldParser.current, &name, &this, state);
}
}
@ -1264,16 +1150,6 @@ static void literal(struct GlobalState * state, int exprType, RewindState *rewin
}
}
static void ellipsis(struct GlobalState * state, int exprType, RewindState *rewind) {
invalidTarget(state, exprType, "literal");
KrkValue value;
if (!krk_tableGet_fast(&vm.builtins->fields, S("Ellipsis"), &value)) {
error("internal compiler error");
return;
}
emitConstant(value);
}
static void typeHintLocal(struct GlobalState * state) {
state->current->enclosing->enclosed = state->current;
state->current = state->current->enclosing;
@ -1287,13 +1163,13 @@ static void typeHintLocal(struct GlobalState * state) {
static void letDeclaration(struct GlobalState * state) {
size_t argCount = 0;
size_t argSpace = 1;
ssize_t * args = KRK_GROW_ARRAY(ssize_t,NULL,0,1);
ssize_t * args = GROW_ARRAY(ssize_t,NULL,0,1);
do {
if (argSpace < argCount + 1) {
size_t old = argSpace;
argSpace = KRK_GROW_CAPACITY(old);
args = KRK_GROW_ARRAY(ssize_t,args,old,argSpace);
argSpace = GROW_CAPACITY(old);
args = GROW_ARRAY(ssize_t,args,old,argSpace);
}
ssize_t ind = parseVariable(state, "Expected variable name.");
if (state->parser.hadError) goto _letDone;
@ -1353,7 +1229,7 @@ static void letDeclaration(struct GlobalState * state) {
}
_letDone:
KRK_FREE_ARRAY(ssize_t,args,argSpace);
FREE_ARRAY(ssize_t,args,argSpace);
return;
}
@ -1786,7 +1662,9 @@ static KrkToken classDeclaration(struct GlobalState * state) {
consume(TOKEN_IDENTIFIER, "Expected class name after 'class'.");
emitByte(OP_PUSH_BUILD_CLASS);
KrkToken buildClass = syntheticToken("__build_class__");
size_t ind = identifierConstant(state, &buildClass);
EMIT_OPERAND_OP(OP_GET_GLOBAL, ind);
Compiler subcompiler;
initCompiler(state, &subcompiler, TYPE_CLASS);
@ -1863,19 +1741,18 @@ _pop_class:
state->currentClass = state->currentClass->enclosing;
KrkCodeObject * makeclass = endCompiler(state);
size_t indFunc = krk_addConstant(currentChunk(), OBJECT_VAL(makeclass));
EMIT_OPERAND_OP(OP_CLOSURE, indFunc);
doUpvalues(state, &subcompiler, makeclass);
freeCompiler(&subcompiler);
RewindState afterFunction = {recordChunk(currentChunk()), krk_tellScanner(&state->scanner), state->parser};
size_t nameInd = nonidentifierTokenConstant(state, &classNameToken);
EMIT_OPERAND_OP(OP_CONSTANT, nameInd);
krk_rewindScanner(&state->scanner, parameters.oldScanner);
state->parser = parameters.oldParser;
EMIT_OPERAND_OP(OP_CLOSURE, indFunc);
doUpvalues(state, &subcompiler, makeclass);
freeCompiler(&subcompiler);
EMIT_OPERAND_OP(OP_CONSTANT, nameInd);
if (match(TOKEN_LEFT_PAREN)) {
call(state, EXPR_CLASS_PARAMETERS, NULL);
} else {
@ -1970,10 +1847,6 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
if (identifiersEqual(&at_classmethod, &state->parser.current)) type = TYPE_CLASSMETHOD;
}
if (level == 0 && inType == TYPE_FUNCTION && state->current->scopeDepth != 0) {
emitByte(OP_NONE);
}
expression(state);
consume(TOKEN_EOL, "Expected end of line after decorator.");
@ -1990,10 +1863,6 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
if (type == TYPE_METHOD && funcName.length == 8 && !memcmp(funcName.start,"__init__",8)) {
type = TYPE_INIT;
}
if (type == TYPE_FUNCTION && state->current->scopeDepth > 0) {
declareVariable(state);
markInitialized(state);
}
function(state, type, blockWidth);
} else if (match(TOKEN_ASYNC)) {
if (!match(TOKEN_DEF)) {
@ -2002,10 +1871,6 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
}
consume(TOKEN_IDENTIFIER, "Expected coroutine name after 'def'.");
funcName = state->parser.previous;
if (type == TYPE_FUNCTION && state->current->scopeDepth > 0) {
declareVariable(state);
markInitialized(state);
}
function(state, type == TYPE_METHOD ? TYPE_COROUTINE_METHOD : TYPE_COROUTINE, blockWidth);
} else if (check(TOKEN_AT)) {
funcName = decorator(state, level+1, type);
@ -2024,12 +1889,10 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
if (level == 0) {
if (inType == TYPE_FUNCTION) {
if (state->current->scopeDepth == 0) {
size_t ind = identifierConstant(state, &funcName);
state->parser.previous = funcName;
declareVariable(state);
size_t ind = (state->current->scopeDepth > 0) ? 0 : identifierConstant(state, &funcName);
defineVariable(state, ind);
} else {
emitByte(OP_SWAP_POP);
}
} else {
size_t ind = identifierConstant(state, &funcName);
rememberClassProperty(state, ind);
@ -2052,9 +1915,7 @@ static void emitLoop(struct GlobalState * state, int loopStart, uint8_t loopType
emitByte(loopType);
int offset = currentChunk()->count - loopStart + ((loopType == OP_LOOP_ITER) ? -1 : 2);
if (offset > 0xFFFF) {
_emitOverlongJump(state, currentChunk()->count, offset);
}
if (offset > 0xFFFF) error("Loop jump offset is too large for opcode.");
emitBytes(offset >> 8, offset);
/* Patch break statements */
@ -2131,6 +1992,9 @@ static void ifStatement(struct GlobalState * state) {
if (state->parser.hadError) return;
int elseJump = emitJump(OP_JUMP);
patchJump(thenJump);
/* See if we have a matching else block */
if (blockWidth == 0 || (check(TOKEN_INDENTATION) && (state->parser.current.length == blockWidth))) {
/* This is complicated */
@ -2140,8 +2004,6 @@ static void ifStatement(struct GlobalState * state) {
advance();
}
if (match(TOKEN_ELSE) || check(TOKEN_ELIF)) {
int elseJump = emitJump(OP_JUMP);
patchJump(thenJump);
if (state->parser.current.type == TOKEN_ELIF || check(TOKEN_IF)) {
state->parser.previous = myPrevious;
ifStatement(state); /* Keep nesting */
@ -2151,8 +2013,6 @@ static void ifStatement(struct GlobalState * state) {
block(state,blockWidth,"else");
endScope(state);
}
patchJump(elseJump);
return;
} else if (!check(TOKEN_EOF) && !check(TOKEN_EOL)) {
if (blockWidth) {
krk_ungetToken(&state->scanner, state->parser.current);
@ -2164,7 +2024,7 @@ static void ifStatement(struct GlobalState * state) {
}
}
patchJump(thenJump);
patchJump(elseJump);
}
static void patchBreaks(struct GlobalState * state, int loopStart) {
@ -2178,8 +2038,8 @@ static void patchBreaks(struct GlobalState * state, int loopStart) {
static void breakStatement(struct GlobalState * state) {
if (state->current->breakSpace < state->current->breakCount + 1) {
size_t old = state->current->breakSpace;
state->current->breakSpace = KRK_GROW_CAPACITY(old);
state->current->breaks = KRK_GROW_ARRAY(struct LoopExit,state->current->breaks,old,state->current->breakSpace);
state->current->breakSpace = GROW_CAPACITY(old);
state->current->breaks = GROW_ARRAY(struct LoopExit,state->current->breaks,old,state->current->breakSpace);
}
if (state->current->loopLocalCount != state->current->localCount) {
@ -2192,8 +2052,8 @@ static void breakStatement(struct GlobalState * state) {
static void continueStatement(struct GlobalState * state) {
if (state->current->continueSpace < state->current->continueCount + 1) {
size_t old = state->current->continueSpace;
state->current->continueSpace = KRK_GROW_CAPACITY(old);
state->current->continues = KRK_GROW_ARRAY(struct LoopExit,state->current->continues,old,state->current->continueSpace);
state->current->continueSpace = GROW_CAPACITY(old);
state->current->continues = GROW_ARRAY(struct LoopExit,state->current->continues,old,state->current->continueSpace);
}
if (state->current->loopLocalCount != state->current->localCount) {
@ -2394,17 +2254,12 @@ static void tryStatement(struct GlobalState * state) {
if (state->parser.hadError) return;
#define EXIT_JUMP_MAX 64
int exitJumps = 2;
#define EXIT_JUMP_MAX 32
int exitJumps = 1;
int exitJumpOffsets[EXIT_JUMP_MAX] = {0};
/* Jump possibly to `else` */
exitJumpOffsets[0] = emitJump(OP_JUMP);
/* Except entry point; ENTER_EXCEPT jumps to `finally` or continues to
* first `except` expression test; may end up redundant if there is only an 'else'. */
patchJump(tryJump);
exitJumpOffsets[1] = emitJump(OP_ENTER_EXCEPT);
int firstJump = 0;
int nextJump = -1;
@ -2420,6 +2275,7 @@ _anotherExcept:
if (exitJumps && !firstJump && match(TOKEN_EXCEPT)) {
if (nextJump != -1) {
patchJump(nextJump);
emitByte(OP_POP);
}
/* Match filter expression (should be class or tuple) */
if (!check(TOKEN_COLON) && !check(TOKEN_AS)) {
@ -2427,26 +2283,26 @@ _anotherExcept:
} else {
emitByte(OP_NONE);
}
nextJump = emitJump(OP_FILTER_EXCEPT);
emitByte(OP_FILTER_EXCEPT);
nextJump = emitJump(OP_JUMP_IF_FALSE_OR_POP);
/* Match 'as' to rename exception */
size_t nameInd = 0;
if (match(TOKEN_AS)) {
consume(TOKEN_IDENTIFIER, "Expected identifier after 'as'.");
state->current->locals[exceptionObject].name = state->parser.previous;
/* `renameLocal` only introduces names for scoped debugging */
nameInd = renameLocal(state, exceptionObject, state->parser.previous);
} else {
state->current->locals[exceptionObject].name = syntheticToken("");
/* XXX Should we remove this now? */
state->current->locals[exceptionObject].name = syntheticToken("exception");
}
size_t nameInd = renameLocal(state, exceptionObject, state->current->locals[exceptionObject].name);
consume(TOKEN_COLON, "Expected ':' after 'except'.");
beginScope(state);
block(state,blockWidth,"except");
endScope(state);
/* Remove scoped name */
if (nameInd) state->current->codeobject->localNames[nameInd].deathday = (size_t)currentChunk()->count;
state->current->codeobject->localNames[nameInd].deathday = (size_t)currentChunk()->count;
if (exitJumps < EXIT_JUMP_MAX) {
exitJumpOffsets[exitJumps++] = emitJump(OP_JUMP);
@ -2461,7 +2317,6 @@ _anotherExcept:
patchJump(exitJumpOffsets[0]);
firstJump = 1;
emitByte(OP_TRY_ELSE);
state->current->locals[exceptionObject].name = syntheticToken("");
beginScope(state);
block(state, blockWidth, "else");
endScope(state);
@ -2477,16 +2332,19 @@ _anotherExcept:
for (int i = firstJump; i < exitJumps; ++i) {
patchJump(exitJumpOffsets[i]);
}
if (nextJump != -1) {
patchJump(nextJump);
}
size_t nameInd = renameLocal(state, exceptionObject, syntheticToken("__tmp"));
emitByte(OP_BEGIN_FINALLY);
exitJumps = 0;
state->current->locals[exceptionObject].name = syntheticToken("");
if (nextJump != -1) {
emitByte(OP_NONE);
patchJump(nextJump);
emitByte(OP_POP);
}
beginScope(state);
block(state,blockWidth,"finally");
endScope(state);
nextJump = -2;
state->current->codeobject->localNames[nameInd].deathday = (size_t)currentChunk()->count;
emitByte(OP_END_FINALLY);
} else if (!check(TOKEN_EOL) && !check(TOKEN_EOF)) {
krk_ungetToken(&state->scanner, state->parser.current);
@ -2504,8 +2362,10 @@ _anotherExcept:
}
if (nextJump >= 0) {
patchJump(nextJump);
emitByte(OP_BEGIN_FINALLY);
emitByte(OP_NONE);
patchJump(nextJump);
emitByte(OP_POP);
emitByte(OP_END_FINALLY);
}
@ -2634,8 +2494,8 @@ static void fromImportStatement(struct GlobalState * state) {
return;
}
while (match(TOKEN_DOT) || match(TOKEN_ELLIPSIS)) {
leadingDots += state->parser.previous.length;
while (match(TOKEN_DOT)) {
leadingDots++;
}
importModule(state, &startOfName, leadingDots);
@ -3090,8 +2950,8 @@ static size_t addUpvalue(struct GlobalState * state, Compiler * compiler, ssize_
}
if (upvalueCount + 1 > compiler->upvaluesSpace) {
size_t old = compiler->upvaluesSpace;
compiler->upvaluesSpace = KRK_GROW_CAPACITY(old);
compiler->upvalues = KRK_GROW_ARRAY(Upvalue,compiler->upvalues,old,compiler->upvaluesSpace);
compiler->upvaluesSpace = GROW_CAPACITY(old);
compiler->upvalues = GROW_ARRAY(Upvalue,compiler->upvalues,old,compiler->upvaluesSpace);
}
compiler->upvalues[upvalueCount].isLocal = isLocal;
compiler->upvalues[upvalueCount].index = index;
@ -3855,8 +3715,6 @@ static void pstar(struct GlobalState * state, int exprType, RewindState *rewind)
}
static void call(struct GlobalState * state, int exprType, RewindState *rewind) {
KrkToken left = rewind ? rewind->oldParser.current : state->parser.previous;
KrkToken this = state->parser.previous;
startEatingWhitespace();
size_t argCount = 0, specialArgs = 0, keywordArgs = 0, seenKeywordUnpacking = 0;
if (!check(TOKEN_RIGHT_PAREN)) {
@ -3955,7 +3813,6 @@ static void call(struct GlobalState * state, int exprType, RewindState *rewind)
} else {
EMIT_OPERAND_OP(OP_CALL, argCount);
}
writeExpressionLocation(&left,&state->parser.previous,&this,state);
invalidTarget(state, exprType, "function call");
}
@ -4126,7 +3983,7 @@ void _createAndBind_compilerClass(void) {
* @return A compiled code object, or NULL on error.
* @exception SyntaxError if @p src could not be compiled.
*/
KrkCodeObject * krk_compile(const char * src, const char * fileName) {
KrkCodeObject * krk_compile(const char * src, char * fileName) {
struct GlobalState * state = (void*)krk_newInstance(KRK_BASE_CLASS(CompilerState));
krk_push(OBJECT_VAL(state));
@ -4250,7 +4107,6 @@ ParseRule krk_parseRules[] = {
RULE(FALSE, literal, NULL, PREC_NONE),
RULE(NONE, literal, NULL, PREC_NONE),
RULE(TRUE, literal, NULL, PREC_NONE),
RULE(ELLIPSIS, ellipsis, NULL, PREC_NONE),
RULE(YIELD, yield, NULL, PREC_NONE),
RULE(AWAIT, await, NULL, PREC_NONE),
RULE(LAMBDA, lambda, NULL, PREC_NONE),

View File

@ -12,109 +12,6 @@
#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
@ -193,39 +90,20 @@ 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 _unused = chunk->code[offset + 1]; size = 2; more; break; } \
case opc ## _LONG: { size_t constant _unused = (chunk->code[offset + 1] << 16) | \
#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) | \
(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]); \
krk_tableSet(AS_DICT(func->jumpTargets), INTEGER_VAL((size_t)(offset + 3 sign jump)), BOOLEAN_VAL(1)); \
if ((size_t)(offset + 3 sign jump) == startPoint) return 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) { \
@ -247,23 +125,16 @@ 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
@ -303,41 +174,6 @@ 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;
@ -346,9 +182,6 @@ static void _overlong_jump_more(OPARGS) {
#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
@ -458,14 +291,34 @@ 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) {
@ -538,6 +391,12 @@ 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)
@ -549,6 +408,12 @@ 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)
@ -560,6 +425,61 @@ 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.
*
@ -696,46 +616,237 @@ int krk_debugBreakpointHandler(void) {
return krk_debuggerHook(frame);
}
void krk_debug_init(void) {
/**
* 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());
vm.dbgState = calloc(1, sizeof(struct DebuggerState));
vm.dbgState->repeatStack_top = -1;
vm.dbgState->repeatStack_bottom = -1;
}
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(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."
);
/* 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, 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.");
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, 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.");
codeobject->expressions[codeobject->expressionsCount] = (KrkExpressionsMap){offset,start,midStart,midEnd,end};
codeobject->expressionsCount++;
}
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.");
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;
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
}
#endif

View File

@ -288,27 +288,12 @@ static void dumpInnerException(KrkValue exception, int depth) {
}
if (line == lineNo) {
fprintf(stderr," ");
unsigned short j = 1;
while (c == ' ' || c == '\t') {
c = fgetc(f);
j++;
}
while (c == ' ') c = fgetc(f);
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));
@ -476,7 +461,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", krk_valuesSame(msg,KWARGS_VAL(0)) ? finishStringBuilder(&sb) : msg);
krk_attachNamedValue(&exceptionObject->fields, "arg", msg == KWARGS_VAL(0) ? finishStringBuilder(&sb) : msg);
krk_attachNamedValue(&exceptionObject->fields, "__cause__", NONE_VAL());
krk_attachNamedValue(&exceptionObject->fields, "__context__", NONE_VAL());
krk_pop();

View File

@ -14,11 +14,6 @@
#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
@ -29,10 +24,10 @@ struct File {
int unowned;
};
#define IS_File(o) (krk_isInstanceOf(o, fileio_File))
#define IS_File(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(File)))
#define AS_File(o) ((struct File*)AS_OBJECT(o))
#define IS_BinaryFile(o) (krk_isInstanceOf(o, fileio_BinaryFile))
#define IS_BinaryFile(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(BinaryFile)))
#define AS_BinaryFile(o) ((struct File*)AS_OBJECT(o))
/**
@ -44,7 +39,7 @@ struct Directory {
DIR * dirPtr;
};
#define IS_Directory(o) (krk_isInstanceOf(o, fileio_Directory))
#define IS_Directory(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(Directory)))
#define AS_Directory(o) ((struct Directory*)AS_OBJECT(o))
#define CURRENT_CTYPE struct File *
@ -82,7 +77,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 ? fileio_BinaryFile : fileio_File);
KrkInstance * fileObject = krk_newInstance(isBinary ? KRK_BASE_CLASS(BinaryFile) : KRK_BASE_CLASS(File));
krk_push(OBJECT_VAL(fileObject));
/* Let's put the filename in there somewhere... */
@ -98,7 +93,7 @@ KRK_Function(open) {
#define BLOCK_SIZE 1024
KRK_Method(File,__repr__) {
KRK_Method(File,__str__) {
METHOD_TAKES_NONE();
KrkValue filename;
KrkValue modestr;
@ -264,7 +259,7 @@ KRK_Method(File,__exit__) {
}
static void makeFileInstance(KrkInstance * module, const char name[], FILE * file, const char mode[]) {
KrkInstance * fileObject = krk_newInstance(fileio_File);
KrkInstance * fileObject = krk_newInstance(KRK_BASE_CLASS(File));
krk_push(OBJECT_VAL(fileObject));
KrkValue filename = OBJECT_VAL(krk_copyString(name,strlen(name)));
krk_push(filename);
@ -438,7 +433,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(fileio_Directory);
struct Directory * dirObj = (void *)krk_newInstance(KRK_BASE_CLASS(Directory));
krk_push(OBJECT_VAL(dirObj));
krk_attachNamedValue(&dirObj->inst.fields, "path", OBJECT_VAL(path));
@ -494,7 +489,11 @@ KRK_Method(Directory,__exit__) {
return FUNC_NAME(Directory,close)(1,argv,0);
}
KRK_Module(fileio) {
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_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 "
@ -503,7 +502,7 @@ KRK_Module(fileio) {
);
/* Define a class to represent files. (Should this be a helper method?) */
KrkClass * File = krk_makeClass(module, &fileio_File, "File", KRK_BASE_CLASS(object));
KrkClass * File = krk_makeClass(module, &KRK_BASE_CLASS(File), "File", KRK_BASE_CLASS(object));
KRK_DOC(File,"Interface to a buffered file stream.");
File->allocSize = sizeof(struct File);
File->_ongcsweep = _file_sweep;
@ -520,14 +519,15 @@ KRK_Module(fileio) {
"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,__repr__);
BIND_METHOD(File,__str__);
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, &fileio_BinaryFile, "BinaryFile", File);
KrkClass * BinaryFile = krk_makeClass(module, &KRK_BASE_CLASS(BinaryFile), "BinaryFile", File);
KRK_DOC(BinaryFile,
"Equivalent to @ref File but using @ref bytes instead of string @ref str."
);
@ -537,7 +537,7 @@ KRK_Module(fileio) {
BIND_METHOD(BinaryFile,write);
krk_finalizeClass(BinaryFile);
KrkClass * Directory = krk_makeClass(module, &fileio_Directory, "Directory", KRK_BASE_CLASS(object));
KrkClass * Directory = krk_makeClass(module, &KRK_BASE_CLASS(Directory), "Directory", KRK_BASE_CLASS(object));
KRK_DOC(Directory,
"Represents an opened file system directory."
);

View File

@ -33,10 +33,11 @@
#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();
@ -127,16 +128,6 @@ 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.
@ -477,7 +468,9 @@ static int debuggerHook(KrkCallFrame * frame) {
krk_pop();
/* Call the compiled expression with no args. */
krk_push(krk_callStack(0));
printResult(stderr, krk_peek(0));
fprintf(stderr, "=> ");
krk_printValue(stderr, krk_peek(0));
fprintf(stderr, "\n");
krk_pop();
}
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
@ -751,6 +744,16 @@ 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);
@ -785,6 +788,11 @@ 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;
@ -830,6 +838,7 @@ 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"
@ -876,26 +885,20 @@ _finishArgs:
/* Bind interrupt signal */
bindSignalHandlers();
#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
#ifdef BUNDLE_LIBS
/* Add any other modules you want to include that are normally built as shared objects. */
BUNDLED(math);
BUNDLED(socket);
BUNDLED(timeit);
#endif
KrkValue result = INTEGER_VAL(0);
char * env_KUROKOPATH = getenv("KUROKOPATH");
char * _KUROKOPATH = getenv("KUROKOPATH");
if (env_KUROKOPATH) {
if (_KUROKOPATH) {
/* Build a path by splitting */
krk_push(OBJECT_VAL(krk_copyString(env_KUROKOPATH,strlen(env_KUROKOPATH))));
krk_push(OBJECT_VAL(krk_copyString(_KUROKOPATH,strlen(_KUROKOPATH))));
krk_push(OBJECT_VAL(S(":")));
/* Split into list */
@ -919,16 +922,12 @@ _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=0,syntax=None\n\n"
"@arguments [prompt], promptwidth=None, 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. "
@ -942,7 +941,10 @@ _finishArgs:
"provide color highlighting of the input line.");
if (moduleAsMain) {
int out = !krk_importModule(AS_STRING(AS_LIST(argList)->values[0]), S("__main__"));
krk_push(OBJECT_VAL(krk_copyString("__main__",8)));
int out = !krk_importModule(
AS_STRING(AS_LIST(argList)->values[0]),
AS_STRING(krk_peek(0)));
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
krk_dumpTraceback();
krk_resetStack();
@ -988,11 +990,12 @@ _finishArgs:
* This module won't be imported by default, but it's still in
* the modules list, so we can look for it there.
*/
if (vm.system) {
KrkValue systemModule;
if (krk_tableGet(&vm.modules, OBJECT_VAL(krk_copyString("kuroko",6)), &systemModule)) {
KrkValue version, buildenv, 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);
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);
fprintf(stdout, "Kuroko %s (%s) with %s\n",
AS_CSTRING(version), AS_CSTRING(builddate), AS_CSTRING(buildenv));
@ -1003,7 +1006,7 @@ _finishArgs:
while (!exitRepl) {
size_t lineCapacity = 8;
size_t lineCount = 0;
char ** lines = KRK_ALLOCATE(char *, lineCapacity);
char ** lines = ALLOCATE(char *, lineCapacity);
size_t totalData = 0;
int valid = 1;
char * allData = NULL;
@ -1089,8 +1092,8 @@ _finishArgs:
if (lineCapacity < lineCount + 1) {
/* If we need more space, grow as needed... */
size_t old = lineCapacity;
lineCapacity = KRK_GROW_CAPACITY(old);
lines = KRK_GROW_ARRAY(char *,lines,old,lineCapacity);
lineCapacity = GROW_CAPACITY(old);
lines = GROW_ARRAY(char *,lines,old,lineCapacity);
}
int i = lineCount++;
@ -1159,13 +1162,26 @@ _finishArgs:
#endif
free(lines[i]);
}
KRK_FREE_ARRAY(char *, lines, lineCapacity);
FREE_ARRAY(char *, lines, lineCapacity);
if (valid) {
KrkValue result = krk_interpret(allData, "<stdin>");
if (!IS_NONE(result)) {
krk_attachNamedValue(&vm.builtins->fields, "_", result);
printResult(stdout, result);
KrkClass * type = krk_getType(result);
const char * formatStr = " => %s\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, " => Unable to produce representation for value.\n");
} else {
fprintf(stdout, formatStr, AS_CSTRING(result));
}
}
krk_resetStack();
free(allData);
@ -1175,6 +1191,20 @@ _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);

View File

@ -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, const char * fileName);
extern KrkCodeObject * krk_compile(const char * src, char * fileName);

View File

@ -206,11 +206,6 @@ 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
*
@ -238,55 +233,4 @@ extern void krk_debug_init(void);
#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

View File

@ -11,37 +11,24 @@
typedef int64_t krk_integer_type;
#ifndef _WIN32
# define KRK_PATH_SEP "/"
# define PATH_SEP "/"
# ifndef KRK_STATIC_ONLY
# include <dlfcn.h>
# 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)
# 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)
# endif
#else
# include <windows.h>
# define KRK_PATH_SEP "\\"
# define 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)
# define dlRefType HINSTANCE
# define dlSymType FARPROC
# define dlOpen(fileName) LoadLibraryA(fileName)
# define dlSym(dlRef, handlerName) GetProcAddress(dlRef, handlerName)
# define 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

View File

@ -7,10 +7,13 @@
#include "object.h"
#include "table.h"
#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))
#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))
/**
* @brief Resize an allocated heap object.

View File

@ -133,27 +133,8 @@ 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
@ -176,13 +157,6 @@ 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;
@ -385,7 +359,7 @@ struct DictValues {
struct KrkModule {
KrkInstance inst;
#ifndef KRK_STATIC_ONLY
krk_dlRefType libHandle;
dlRefType libHandle;
#endif
};

View File

@ -111,8 +111,6 @@ typedef enum {
TOKEN_RETRY,
TOKEN_ERROR,
TOKEN_EOF,
TOKEN_ELLIPSIS, /* ... */
} KrkTokenType;
/**

View File

@ -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,11 +26,9 @@ typedef struct {
* @brief Simple hash table of arbitrary keys to values.
*/
typedef struct {
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. */
size_t count;
size_t capacity;
KrkTableEntry * entries;
} KrkTable;
/**
@ -155,6 +153,21 @@ 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

View File

@ -33,30 +33,6 @@
#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'", \
@ -94,11 +70,23 @@
#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 _unused = AS_ ## type (argv[i])
ctype name __attribute__((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)
@ -365,18 +353,3 @@ extern int krk_pushStringBuilderFormat(struct StringBuilder * sb, const char * f
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)

View File

@ -7,7 +7,6 @@
#include <string.h>
#include "kuroko.h"
#ifndef KRK_NO_NAN_BOXING
/**
* @brief Tag enum for basic value types.
*
@ -24,6 +23,28 @@ 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.
@ -40,32 +61,6 @@ 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.
*
@ -115,6 +110,42 @@ 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
@ -138,7 +169,7 @@ extern int krk_valuesEqual(KrkValue a, KrkValue b);
*
* @return 1 if values represent the same object or value, 0 otherwise.
*/
static inline int krk_valuesSame(KrkValue a, KrkValue b) { return _krk_valuesSame(a,b); }
extern int krk_valuesSame(KrkValue a, KrkValue b);
/**
* @brief Compare two values by identity, then by equality.
@ -151,37 +182,12 @@ static inline int krk_valuesSame(KrkValue a, KrkValue b) { return _krk_valuesSam
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.
@ -207,13 +213,13 @@ static inline uintptr_t _krk_sanitize(uintptr_t input) {
#define KRK_HEAP_TAG 0
#endif
#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 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 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)((uint64_t)((((uint64_t)ty) << 32) | ((uint32_t)ta)) | KRK_VAL_MASK_HANDLER))
#define HANDLER_VAL(ty,ta) ((KrkValue)((uint32_t)((((uint16_t)ty) << 16) | ((uint16_t)ta)) | KRK_VAL_MASK_HANDLER))
#define FLOATING_VAL(value) (((KrkValueDbl){.dbl = (value)}).val)
#define KRK_VAL_TYPE(value) ((value) >> 48)
@ -224,7 +230,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) ((uint64_t)((value) & KRK_VAL_MASK_LOW))
#define AS_HANDLER(value) ((uint32_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)
@ -243,49 +249,8 @@ 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)
#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 AS_HANDLER_TYPE(value) (AS_HANDLER(value) >> 16)
#define AS_HANDLER_TARGET(value) (AS_HANDLER(value) & 0xFFFF)
#define IS_HANDLER_TYPE(value,type) (IS_HANDLER(value) && AS_HANDLER_TYPE(value) == type)
#define KWARGS_SINGLE (INT32_MAX)

View File

@ -7,7 +7,9 @@
* 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"
@ -17,7 +19,7 @@
* @def KRK_CALL_FRAMES_MAX
* @brief Maximum depth of the call stack in managed-code function calls.
*/
#define KRK_CALL_FRAMES_MAX 1000
#define KRK_CALL_FRAMES_MAX 64
/**
* @def KRK_THREAD_SCRATCH_SIZE
@ -48,6 +50,9 @@ 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;
/**
@ -131,13 +136,17 @@ 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 * CompilerStateClass; /**< Compiler global state */
KrkClass * CellClass; /**< Upvalue cell */
KrkClass * FileClass; /**< os.File */
KrkClass * BinaryFileClass; /**< os.BinaryFile */
KrkClass * DirectoryClass; /**< os.Directory */
KrkClass * stat_resultClass; /**< stat.stat_result */
KrkClass * EnvironClass; /**< os._Environ */
KrkClass * setClass; /**< Unordered hashset */
KrkClass * setiteratorClass; /**< Iterator over values in a set */
KrkClass * ThreadClass; /**< Threading.Thread */
KrkClass * LockClass; /**< Threading.Lock */
KrkClass * ellipsisClass; /**< Type of the Ellipsis (...) singleton */
KrkClass * CompilerStateClass; /**< Compiler global state */
KrkClass * CellClass; /**< Upvalue cell */
};
/**
@ -163,7 +172,6 @@ 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. */
@ -197,6 +205,8 @@ 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;
@ -213,15 +223,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)
/* 11 is available again */
#define KRK_GLOBAL_CALLGRIND (1 << 11)
#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 krk_threadLocal __thread
# define threadLocal __thread
#else
# define krk_threadLocal
# define threadLocal
#endif
/**
@ -242,7 +252,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 krk_threadLocal KrkThreadState krk_currentThread;
extern threadLocal KrkThreadState krk_currentThread;
#endif
/**
@ -311,7 +321,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, const char * fromFile);
extern KrkValue krk_interpret(const char * src, char * fromFile);
/**
* @brief Load and run a source file and return when execution completes.
@ -325,7 +335,7 @@ extern KrkValue krk_interpret(const char * src, const 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, const char * fromFile);
extern KrkValue krk_runfile(const char * fileName, char * fromFile);
/**
* @brief Push a stack value.
@ -985,6 +995,33 @@ 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.
*

View File

@ -1,4 +1,3 @@
#include <time.h>
#include <kuroko/vm.h>
#include <kuroko/memory.h>
#include <kuroko/object.h>
@ -8,8 +7,6 @@
#include "private.h"
#define FREE_OBJECT(t,p) krk_reallocate(p,sizeof(t),0)
#if defined(KRK_EXTENSIVE_MEMORY_DEBUGGING)
/**
* Extensive Memory Debugging
@ -21,7 +18,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 KRK_FREE_ARRAY macros, for example, and the memory tracking now has
* @c 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
@ -205,9 +202,9 @@ static void freeObject(KrkObj * object) {
switch (object->type) {
case KRK_OBJ_STRING: {
KrkString * string = (KrkString*)object;
KRK_FREE_ARRAY(char, string->chars, string->length + 1);
FREE_ARRAY(char, string->chars, string->length + 1);
if (string->codes && string->codes != string->chars) free(string->codes);
FREE_OBJECT(KrkString, object);
FREE(KrkString, object);
break;
}
case KRK_OBJ_CODEOBJECT: {
@ -215,26 +212,24 @@ static void freeObject(KrkObj * object) {
krk_freeChunk(&function->chunk);
krk_freeValueArray(&function->positionalArgNames);
krk_freeValueArray(&function->keywordArgNames);
KRK_FREE_ARRAY(KrkLocalEntry, function->localNames, function->localNameCount);
KRK_FREE_ARRAY(KrkExpressionsMap, function->expressions, function->expressionsCapacity);
KRK_FREE_ARRAY(KrkOverlongJump, function->overlongJumps, function->overlongJumpsCapacity);
FREE_ARRAY(KrkLocalEntry, function->localNames, function->localNameCount);
function->localNameCount = 0;
FREE_OBJECT(KrkCodeObject, object);
FREE(KrkCodeObject, object);
break;
}
case KRK_OBJ_NATIVE: {
FREE_OBJECT(KrkNative, object);
FREE(KrkNative, object);
break;
}
case KRK_OBJ_CLOSURE: {
KrkClosure * closure = (KrkClosure*)object;
KRK_FREE_ARRAY(KrkUpvalue*,closure->upvalues,closure->upvalueCount);
FREE_ARRAY(KrkUpvalue*,closure->upvalues,closure->upvalueCount);
krk_freeTable(&closure->fields);
FREE_OBJECT(KrkClosure, object);
FREE(KrkClosure, object);
break;
}
case KRK_OBJ_UPVALUE: {
FREE_OBJECT(KrkUpvalue, object);
FREE(KrkUpvalue, object);
break;
}
case KRK_OBJ_CLASS: {
@ -244,7 +239,7 @@ static void freeObject(KrkObj * object) {
if (_class->base) {
krk_tableDeleteExact(&_class->base->subclasses, OBJECT_VAL(object));
}
FREE_OBJECT(KrkClass, object);
FREE(KrkClass, object);
break;
}
case KRK_OBJ_INSTANCE: {
@ -257,18 +252,18 @@ static void freeObject(KrkObj * object) {
break;
}
case KRK_OBJ_BOUND_METHOD:
FREE_OBJECT(KrkBoundMethod, object);
FREE(KrkBoundMethod, object);
break;
case KRK_OBJ_TUPLE: {
KrkTuple * tuple = (KrkTuple*)object;
krk_freeValueArray(&tuple->values);
FREE_OBJECT(KrkTuple, object);
FREE(KrkTuple, object);
break;
}
case KRK_OBJ_BYTES: {
KrkBytes * bytes = (KrkBytes*)object;
KRK_FREE_ARRAY(uint8_t, bytes->bytes, bytes->length);
FREE_OBJECT(KrkBytes, bytes);
FREE_ARRAY(uint8_t, bytes->bytes, bytes->length);
FREE(KrkBytes, bytes);
break;
}
}
@ -324,7 +319,7 @@ void krk_markObject(KrkObj * object) {
object->flags |= KRK_OBJ_FLAGS_IS_MARKED;
if (vm.grayCapacity < vm.grayCount + 1) {
vm.grayCapacity = KRK_GROW_CAPACITY(vm.grayCapacity);
vm.grayCapacity = GROW_CAPACITY(vm.grayCapacity);
vm.grayStack = realloc(vm.grayStack, sizeof(KrkObj*) * vm.grayCapacity);
if (!vm.grayStack) exit(1);
}
@ -367,7 +362,6 @@ 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:
@ -442,7 +436,7 @@ static size_t sweep(void) {
}
void krk_markTable(KrkTable * table) {
for (size_t i = 0; i < table->used; ++i) {
for (size_t i = 0; i < table->capacity; ++i) {
KrkTableEntry * entry = &table->entries[i];
krk_markValue(entry->key);
krk_markValue(entry->value);
@ -450,7 +444,7 @@ void krk_markTable(KrkTable * table) {
}
static void tableRemoveWhite(KrkTable * table) {
for (size_t i = 0; i < table->used; ++i) {
for (size_t i = 0; i < table->capacity; ++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);
@ -568,3 +562,42 @@ 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

View File

@ -62,10 +62,4 @@ 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__")

View File

@ -1,315 +0,0 @@
/**
* @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);
}

View File

@ -1,376 +0,0 @@
#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
}

View File

@ -1,31 +0,0 @@
#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 ");
}

View File

@ -1,99 +0,0 @@
#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
}

View File

@ -148,7 +148,10 @@ MATH_IS(isnan)
#define bind(name) krk_defineNative(&module->fields, #name, _math_ ## name)
KRK_Module(math) {
KrkValue krk_module_onload_math(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_push(OBJECT_VAL(module));
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"
@ -268,4 +271,7 @@ KRK_Module(math) {
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);
}

View File

@ -58,11 +58,16 @@ KRK_Function(seed) {
return NONE_VAL();
}
KRK_Module(random) {
KrkValue krk_module_onload_random(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_push(OBJECT_VAL(module));
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();
}

View File

@ -513,7 +513,10 @@ KRK_Method(socket,proto) {
return INTEGER_VAL(self->proto);
}
KRK_Module(socket) {
KrkValue krk_module_onload_socket(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_push(OBJECT_VAL(module));
KRK_DOC(module, "Lightweight wrapper around the standard Berkeley sockets interface.");
KrkClass * socket = krk_makeClass(module, &SocketClass, "socket", vm.baseClasses->objectClass);
@ -570,6 +573,7 @@ KRK_Module(socket) {
BIND_PROP(socket,type);
BIND_PROP(socket,proto);
krk_defineNative(&socket->methods,"__str__", FUNC_NAME(socket,__repr__));
krk_finalizeClass(SocketClass);
BIND_FUNC(module, htons);
@ -619,4 +623,6 @@ KRK_Module(socket) {
krk_makeClass(module, &SocketError, "SocketError", vm.exceptions->baseException);
KRK_DOC(SocketError, "Raised on faults from socket functions.");
krk_finalizeClass(SocketError);
return krk_pop();
}

View File

@ -1,57 +0,0 @@
#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
}

View File

@ -1,276 +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);
}
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.");
}

View File

@ -35,8 +35,14 @@ KRK_Function(timeit) {
return FLOATING_VAL(after-before);
}
KRK_Module(timeit) {
KrkValue krk_module_onload_timeit(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_push(OBJECT_VAL(module));
KRK_DOC(module, "@brief Run functions very quickly without loop overhead from the interpreter.");
BIND_FUNC(module,timeit);
krk_pop();
return OBJECT_VAL(module);
}

View File

@ -17,12 +17,16 @@ KRK_Function(wcwidth) {
return INTEGER_VAL(wcwidth(codepoint));
}
KRK_Module(wcwidth) {
KrkValue krk_module_onload_wcwidth(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_push(OBJECT_VAL(module));
KRK_DOC(module, "Character widths.");
BIND_FUNC(module, wcwidth);
#ifndef _WIN32
setlocale(LC_ALL, "");
#endif
return krk_pop();
}

View File

@ -135,7 +135,7 @@ KRK_Method(type,__file__) {
return self->filename ? OBJECT_VAL(self->filename) : NONE_VAL();
}
KRK_Method(type,__repr__) {
KRK_Method(type,__str__) {
/* Determine if this class has a module */
KrkValue module = NONE_VAL();
krk_tableGet(&self->methods, OBJECT_VAL(S("__module__")), &module);
@ -185,12 +185,7 @@ KRK_Method(type,__call__) {
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 */
/* Push args */
int argCount = argc;
for (int i = 0; i < argc; ++i) {
krk_push(argv[i]);
@ -203,24 +198,18 @@ KRK_Method(type,__call__) {
krk_push(KWARGS_VAL(1));
}
result = krk_callDirect(self->_new, argCount);
}
krk_push(krk_callDirect(self->_new, argCount));
/* If an exception happened in __new__, don't try to call __init__ even if the conditions would be right. */
/* Exception here */
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;
if (krk_isInstanceOf(krk_peek(0), self) && likely(self->_init != NULL)) {
krk_push(krk_peek(0));
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));
@ -231,10 +220,9 @@ KRK_Method(type,__call__) {
fprintf(stderr, "Warning: Non-None result returned from %s.__init__\n",
self->name->chars);
}
return krk_pop();
}
return result;
return krk_pop();
}
_noexport
@ -246,11 +234,12 @@ void _createAndBind_type(void) {
BIND_PROP(type,__file__);
BIND_PROP(type,__name__);
BIND_METHOD(type,__repr__);
BIND_METHOD(type,__str__);
BIND_METHOD(type,__subclasses__);
BIND_METHOD(type,__getitem__);
BIND_METHOD(type,__call__);
BIND_STATICMETHOD(type,__new__);
krk_defineNative(&type->methods,"__repr__",FUNC_NAME(type,__str__));
krk_finalizeClass(type);
KRK_DOC(type, "Obtain the object representation of the class of an object.");

View File

@ -304,7 +304,6 @@ 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");
}
@ -325,10 +324,15 @@ KRK_Method(bytearray,__repr__) {
METHOD_TAKES_NONE();
struct StringBuilder sb = {0};
pushStringBuilderStr(&sb, "bytearray(", 10);
if (!krk_pushStringBuilderFormat(&sb, "%R", self->actual)) {
krk_discardStringBuilder(&sb);
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);
return NONE_VAL();
}
pushStringBuilderStr(&sb, AS_STRING(repred_bytes)->chars, AS_STRING(repred_bytes)->length);
pushStringBuilder(&sb,')');
return finishStringBuilder(&sb);
}
@ -432,6 +436,7 @@ 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);
@ -456,5 +461,6 @@ 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);
}

View File

@ -4,14 +4,6 @@
#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`...
@ -21,16 +13,10 @@ 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);
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);
krk_tableAdjustCapacity(&((KrkDict*)outDict)->entries, argc);
for (int ind = 0; ind < argc; ind += 2) {
krk_tableSet(&((KrkDict*)outDict)->entries, argv[ind], argv[ind+1]);
}
}
return krk_pop();
}
@ -167,8 +153,8 @@ KRK_Method(dict,__len__) {
KRK_Method(dict,__contains__) {
METHOD_TAKES_EXACTLY(1);
KrkValue v;
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &v));
KrkValue _unused;
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &_unused));
}
KRK_Method(dict,capacity) {
@ -188,21 +174,35 @@ 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) pushStringBuilderStr(&sb, ", ", 2);
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
}
c++;
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
{
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);
}
}
pushStringBuilderStr(&sb, ": ", 2);
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->value)) goto _error;
{
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);
}
}
}
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) {
@ -328,7 +328,7 @@ KRK_Method(dictitems,__iter__) {
KRK_Method(dictitems,__call__) {
do {
if (self->i >= AS_DICT(self->dict)->used) return argv[0];
if (self->i >= AS_DICT(self->dict)->capacity) return argv[0];
if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
KrkTuple * outValue = krk_newTuple(2);
krk_push(OBJECT_VAL(outValue));
@ -350,27 +350,43 @@ KRK_Method(dictitems,__repr__) {
pushStringBuilderStr(&sb,"dictitems([",11);
size_t c = 0;
size_t len = AS_DICT(self->dict)->used;
size_t len = AS_DICT(self->dict)->capacity;
for (size_t i = 0; i < len; ++i) {
KrkTableEntry * entry = &AS_DICT(self->dict)->entries[i];
if (IS_KWARGS(entry->key)) continue;
if (c) pushStringBuilderStr(&sb, ", ", 2);
c++;
pushStringBuilder(&sb,'(');
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->value)) goto _error;
}
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);
}
}
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);
}
}
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
@ -397,7 +413,7 @@ KRK_Method(dictkeys,__iter__) {
KRK_Method(dictkeys,__call__) {
METHOD_TAKES_NONE();
do {
if (self->i >= AS_DICT(self->dict)->used) return argv[0];
if (self->i >= AS_DICT(self->dict)->capacity) 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++;
@ -415,23 +431,28 @@ KRK_Method(dictkeys,__repr__) {
pushStringBuilderStr(&sb,"dictkeys([",10);
size_t c = 0;
size_t len = AS_DICT(self->dict)->used;
size_t len = AS_DICT(self->dict)->capacity;
for (size_t i = 0; i < len; ++i) {
KrkTableEntry * entry = &AS_DICT(self->dict)->entries[i];
if (IS_KWARGS(entry->key)) continue;
if (c) pushStringBuilderStr(&sb, ", ", 2);
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
}
c++;
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
{
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);
}
}
}
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
@ -458,7 +479,7 @@ KRK_Method(dictvalues,__iter__) {
KRK_Method(dictvalues,__call__) {
METHOD_TAKES_NONE();
do {
if (self->i >= AS_DICT(self->dict)->used) return argv[0];
if (self->i >= AS_DICT(self->dict)->capacity) 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++;
@ -476,23 +497,28 @@ KRK_Method(dictvalues,__repr__) {
pushStringBuilderStr(&sb,"dictvalues([",12);
size_t c = 0;
size_t len = AS_DICT(self->dict)->used;
size_t len = AS_DICT(self->dict)->capacity;
for (size_t i = 0; i < len; ++i) {
KrkTableEntry * entry = &AS_DICT(self->dict)->entries[i];
if (IS_KWARGS(entry->key)) continue;
if (c) pushStringBuilderStr(&sb, ", ", 2);
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
}
c++;
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->value)) goto _error;
{
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);
}
}
}
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
@ -521,6 +547,7 @@ 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);

View File

@ -137,7 +137,7 @@ KRK_Method(function,_ip_to_line) {
return INTEGER_VAL(line);
}
KRK_Method(function,__repr__) {
KRK_Method(function,__str__) {
METHOD_TAKES_NONE();
/* Do we have a qualified name? */
@ -215,7 +215,7 @@ KRK_Method(codeobject,__name__) {
return self->name ? OBJECT_VAL(self->name) : OBJECT_VAL(S(""));
}
KRK_Method(codeobject,__repr__) {
KRK_Method(codeobject,__str__) {
METHOD_TAKES_NONE();
KrkValue s = FUNC_NAME(codeobject,__name__)(1,argv,0);
if (!IS_STRING(s)) return NONE_VAL();
@ -303,10 +303,6 @@ 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*
@ -334,7 +330,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,__repr__) {
KRK_Method(method,__str__) {
METHOD_TAKES_NONE();
KrkValue s = FUNC_NAME(method,__qualname__)(1,argv,0);
if (!IS_STRING(s)) s = FUNC_NAME(method,__name__)(1,argv,0);
@ -383,7 +379,7 @@ KRK_Method(method,__func__) {
KRK_Method(method,__self__) {
ATTRIBUTE_NOT_ASSIGNABLE();
return self->receiver;
return OBJECT_VAL(self->receiver);
}
KRK_Function(staticmethod) {
@ -408,7 +404,7 @@ void _createAndBind_functionClass(void) {
codeobject->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
codeobject->allocSize = 0;
BIND_STATICMETHOD(codeobject,__new__);
BIND_METHOD(codeobject,__repr__);
BIND_METHOD(codeobject,__str__);
BIND_METHOD(codeobject,_ip_to_line);
BIND_PROP(codeobject,__constants__);
BIND_PROP(codeobject,__name__);
@ -419,14 +415,14 @@ void _createAndBind_functionClass(void) {
BIND_PROP(codeobject,co_posonlyargcount);
BIND_PROP(codeobject,__locals__);
BIND_PROP(codeobject,__args__);
BIND_PROP(codeobject,__file__);
krk_defineNative(&codeobject->methods, "__repr__", FUNC_NAME(codeobject,__str__));
krk_finalizeClass(codeobject);
KrkClass * function = ADD_BASE_CLASS(vm.baseClasses->functionClass, "function", vm.baseClasses->objectClass);
function->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
function->allocSize = 0;
BIND_STATICMETHOD(function,__new__);
BIND_METHOD(function,__repr__);
BIND_METHOD(function,__str__);
BIND_METHOD(function,_ip_to_line);
BIND_PROP(function,__doc__);
BIND_PROP(function,__name__);
@ -437,6 +433,7 @@ void _createAndBind_functionClass(void) {
BIND_PROP(function,__code__);
BIND_PROP(function,__globals__);
BIND_PROP(function,__closure__);
krk_defineNative(&function->methods, "__repr__", FUNC_NAME(function,__str__));
krk_defineNative(&function->methods, "__class_getitem__", krk_GenericAlias)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
krk_finalizeClass(function);
@ -444,7 +441,7 @@ void _createAndBind_functionClass(void) {
method->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
method->allocSize = 0;
BIND_STATICMETHOD(method,__new__);
BIND_METHOD(method,__repr__);
BIND_METHOD(method,__str__);
BIND_METHOD(method,_ip_to_line);
BIND_PROP(method,__doc__);
BIND_PROP(method,__name__);
@ -455,6 +452,7 @@ 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.");

View File

@ -272,5 +272,6 @@ 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);
}

View File

@ -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 = KRK_GROW_ARRAY(KrkValue, AS_LIST(outList)->values, 0, argc);
AS_LIST(outList)->values = GROW_ARRAY(KrkValue, AS_LIST(outList)->values, 0, argc);
memcpy(AS_LIST(outList)->values, argv, sizeof(KrkValue) * argc);
AS_LIST(outList)->count = argc;
}
@ -138,7 +138,15 @@ KRK_Method(list,__repr__) {
pushStringBuilder(&sb, '[');
pthread_rwlock_rdlock(&self->rwlock);
for (size_t i = 0; i < self->values.count; ++i) {
if (!krk_pushStringBuilderFormat(&sb,"%R",self->values.values[i])) goto _error;
/* 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 (i + 1 < self->values.count) {
pushStringBuilderStr(&sb, ", ", 2);
}
@ -148,20 +156,14 @@ 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) ? KRK_GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = KRK_GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
positionals->capacity = (count == 1) ? GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
}
for (size_t i = 0; i < count; ++i) {
@ -304,7 +306,7 @@ KRK_Method(list,__delitem__) {
METHOD_TAKES_EXACTLY(1);
if (IS_INTEGER(argv[1])) {
FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0],argv[1]},0);
FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0],INTEGER_VAL(argv[1])},0);
} else if (IS_slice(argv[1])) {
KRK_SLICER(argv[1],self->values.count) {
return NONE_VAL();
@ -414,338 +416,36 @@ 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);
if (self->values.count > 1) reverse_values(self->values.values, self->values.count);
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;
}
pthread_rwlock_unlock(&self->rwlock);
return NONE_VAL();
}
struct SortSlice {
KrkValue * keys;
KrkValue * values;
};
static int _list_sorter(const void * _a, const void * _b) {
KrkValue a = *(KrkValue*)_a;
KrkValue b = *(KrkValue*)_b;
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);
/* 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;
}
KRK_Method(list,sort) {
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();
METHOD_TAKES_NONE();
pthread_rwlock_wrlock(&self->rwlock);
powersort(self, key, reverse);
qsort(self->values.values, self->values.count, sizeof(KrkValue), _list_sorter);
pthread_rwlock_unlock(&self->rwlock);
return NONE_VAL();
@ -821,7 +521,7 @@ KRK_Method(listiterator,__init__) {
}
FUNC_SIG(listiterator,__call__) {
static _unused const char* _method_name = "__call__";
static __attribute__ ((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;
@ -844,18 +544,18 @@ _bad:
goto _maybeGood;
}
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);
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);
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,(KrkValue[]){listOut,hasKw ? argv[1] : NONE_VAL(), hasKw ? argv[2] : NONE_VAL()},hasKw);
FUNC_NAME(list,sort)(1,&listOut,0);
if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL();
return krk_pop();
}
KRK_Function(reversed) {
static KrkValue _reversed(int argc, const KrkValue argv[], int hasKw) {
/* 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);
@ -940,16 +640,17 @@ 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", FUNC_NAME(krk,sorted),
BUILTIN_FUNCTION("sorted", _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", FUNC_NAME(krk,reversed),
BUILTIN_FUNCTION("reversed", _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.");

File diff suppressed because it is too large Load Diff

View File

@ -23,13 +23,7 @@ KRK_StaticMethod(int,__new__) {
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"},
if (!krk_parseArgs("O|V?i?:int", (const char*[]){"cls","x","base"},
&cls, &has_x, &x, &has_base, &base)) return NONE_VAL();
if (has_base && (base < 2 || base > 36) && base != 0) {
@ -48,13 +42,6 @@ KRK_StaticMethod(int,__new__) {
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)) {
@ -64,11 +51,17 @@ _just_x:
return result;
}
if (IS_BOOLEAN(x)) return INTEGER_VAL(AS_INTEGER(x));
if (IS_INTEGER(x)) return x;
if (krk_isInstanceOf(x, KRK_BASE_CLASS(long))) return x;
#ifndef KRK_NO_FLOAT
if (IS_FLOATING(x)) return krk_int_from_float(AS_FLOATING(x));
#endif
if (IS_BOOLEAN(x)) return INTEGER_VAL(AS_BOOLEAN(x));
return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "int", x);
}
KRK_Method(int,__repr__) {
KRK_Method(int,__str__) {
char tmp[100];
size_t l = snprintf(tmp, 100, PRIkrk_int, self);
return OBJECT_VAL(krk_copyString(tmp, l));
@ -243,7 +236,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 == ',' || base == 10) ? 3 : 4;
int sepcount = opts.sep == ',' ? 3 : 4;
int more = 0;
if (prepCallback) callback = prepCallback(abs, base);
@ -624,94 +617,24 @@ KRK_StaticMethod(float,__new__) {
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 krk_int_from_float(self); }
KRK_Method(float,__int__) { return INTEGER_VAL(self); }
KRK_Method(float,__float__) { return argv[0]; }
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);
static int isDigits(const char * c) {
while (*c) {
if (*c != '-' && (*c < '0' || *c > '9')) return 0;
c++;
}
return 1;
}
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");
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);
}
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);
return OBJECT_VAL(krk_copyString(tmp, l));
}
KRK_Method(float,__eq__) {
@ -813,11 +736,6 @@ KRK_Method(float,__rfloordiv__) {
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
@ -829,7 +747,7 @@ KRK_StaticMethod(bool,__new__) {
return BOOLEAN_VAL(!krk_isFalsey(argv[1]));
}
KRK_Method(bool,__repr__) {
KRK_Method(bool,__str__) {
return OBJECT_VAL((self ? S("True") : S("False")));
}
@ -838,7 +756,7 @@ KRK_Method(bool,__format__) {
CHECK_ARG(1,str,KrkString*,format_spec);
if (!format_spec->length) {
return FUNC_NAME(bool,__repr__)(argc,argv,hasKw);
return FUNC_NAME(bool,__str__)(argc,argv,hasKw);
} else {
return FUNC_NAME(int,__format__)(argc,argv,hasKw);
}
@ -849,7 +767,7 @@ KRK_StaticMethod(NoneType,__new__) {
return NONE_VAL();
}
KRK_Method(NoneType,__repr__) {
KRK_Method(NoneType,__str__) {
return OBJECT_VAL(S("None"));
}
@ -871,7 +789,7 @@ KRK_StaticMethod(NotImplementedType,__new__) {
return NOTIMPL_VAL();
}
KRK_Method(NotImplementedType,__repr__) {
KRK_Method(NotImplementedType,__str__) {
return OBJECT_VAL(S("NotImplemented"));
}
@ -900,7 +818,7 @@ void _createAndBind_numericClasses(void) {
_int->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
_int->allocSize = 0;
BIND_STATICMETHOD(int,__new__);
BIND_METHOD(int,__repr__);
BIND_METHOD(int,__str__);
BIND_METHOD(int,__int__);
BIND_METHOD(int,__chr__);
BIND_METHOD(int,__eq__);
@ -937,6 +855,7 @@ 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.");
@ -947,7 +866,7 @@ void _createAndBind_numericClasses(void) {
BIND_STATICMETHOD(float,__new__);
BIND_METHOD(float,__int__);
BIND_METHOD(float,__float__);
BIND_METHOD(float,__repr__);
BIND_METHOD(float,__str__);
BIND_METHOD(float,__eq__);
BIND_METHOD(float,__hash__);
BIND_TRIPLET(float,add);
@ -962,8 +881,7 @@ void _createAndBind_numericClasses(void) {
BIND_METHOD(float,__neg__);
BIND_METHOD(float,__abs__);
BIND_METHOD(float,__pos__);
BIND_METHOD(float,__format__);
BIND_METHOD(float,as_integer_ratio);
krk_defineNative(&_float->methods, "__repr__", FUNC_NAME(float,__str__));
#endif
krk_finalizeClass(_float);
KRK_DOC(_float, "Convert a number or string type to a float representation.");
@ -971,8 +889,9 @@ void _createAndBind_numericClasses(void) {
KrkClass * _bool = ADD_BASE_CLASS(vm.baseClasses->boolClass, "bool", vm.baseClasses->intClass);
_bool->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_STATICMETHOD(bool,__new__);
BIND_METHOD(bool,__repr__);
BIND_METHOD(bool,__str__);
BIND_METHOD(bool,__format__);
krk_defineNative(&_bool->methods, "__repr__", FUNC_NAME(bool,__str__));
krk_finalizeClass(_bool);
KRK_DOC(_bool, "Returns False if the argument is 'falsey', otherwise True.");
@ -980,18 +899,20 @@ void _createAndBind_numericClasses(void) {
_NoneType->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
_NoneType->allocSize = 0;
BIND_STATICMETHOD(NoneType, __new__);
BIND_METHOD(NoneType, __repr__);
BIND_METHOD(NoneType, __str__);
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;
_NotImplementedType->allocSize = 0;
BIND_STATICMETHOD(NotImplementedType, __new__);
BIND_METHOD(NotImplementedType, __repr__);
BIND_METHOD(NotImplementedType, __str__);
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());

View File

@ -63,13 +63,13 @@ KRK_Method(set,__init__) {
KRK_Method(set,__contains__) {
METHOD_TAKES_EXACTLY(1);
KrkValue v;
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &v));
KrkValue _unused;
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &_unused));
}
KRK_Method(set,__repr__) {
METHOD_TAKES_NONE();
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL(S("{...}"));
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL("{...}");
if (!self->entries.capacity) return OBJECT_VAL(S("set()"));
((KrkObj*)self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
struct StringBuilder sb = {0};
@ -80,19 +80,22 @@ 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) pushStringBuilderStr(&sb, ", ", 2);
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
}
c++;
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
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);
}
}
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__) {
@ -195,11 +198,11 @@ KRK_Method(set,__eq__) {
if (self->entries.count != them->entries.count)
return BOOLEAN_VAL(0);
KrkValue v;
KrkValue _unused;
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, &v)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
@ -213,10 +216,10 @@ KRK_Method(set,__lt__) {
struct Set * them = AS_set(argv[1]);
if (self->entries.count == them->entries.count)
return BOOLEAN_VAL(0);
KrkValue v;
KrkValue _unused;
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, &v)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
@ -227,10 +230,10 @@ KRK_Method(set,__le__) {
if (!IS_set(argv[1]))
return NOTIMPL_VAL();
struct Set * them = AS_set(argv[1]);
KrkValue v;
KrkValue _unused;
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, &v)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
@ -243,10 +246,10 @@ KRK_Method(set,__gt__) {
struct Set * them = AS_set(argv[1]);
if (self->entries.count == them->entries.count)
return BOOLEAN_VAL(0);
KrkValue v;
KrkValue _unused;
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, &v)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
@ -256,10 +259,10 @@ KRK_Method(set,__ge__) {
if (!IS_set(argv[1]))
return NOTIMPL_VAL();
struct Set * them = AS_set(argv[1]);
KrkValue v;
KrkValue _unused;
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, &v)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
@ -388,6 +391,7 @@ void _createAndBind_setClass(void) {
"@brief Empty the set.\n\n"
"Removes all elements from the set, in-place.");
BIND_METHOD(set,update);
krk_defineNative(&set->methods, "__str__", FUNC_NAME(set,__repr__));
krk_attachNamedValue(&set->methods, "__hash__", NONE_VAL());
krk_finalizeClass(set);

View File

@ -118,24 +118,37 @@ KRK_Method(slice,__init__) {
KRK_Method(slice,__repr__) {
METHOD_TAKES_NONE();
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL(S("slice(...)"));
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL("slice(...)");
((KrkObj*)self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
struct StringBuilder sb = {0};
pushStringBuilderStr(&sb,"slice(",6);
KrkClass * type;
KrkValue result;
/* start */
if (!krk_pushStringBuilderFormat(&sb, "%R", self->start)) goto _error;
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);
pushStringBuilderStr(&sb,", ",2);
if (!krk_pushStringBuilderFormat(&sb, "%R", self->end)) goto _error;
/* 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);
pushStringBuilderStr(&sb,", ",2);
if (!krk_pushStringBuilderFormat(&sb, "%R", self->step)) goto _error;
/* 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);
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) {
@ -153,30 +166,9 @@ 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(KRK_BASE_CLASS(slice), "slice", KRK_BASE_CLASS(object));
KrkClass * slice = ADD_BASE_CLASS(vm.baseClasses->sliceClass, "slice", vm.baseClasses->objectClass);
slice->allocSize = sizeof(struct KrkSlice);
slice->_ongcscan = _slice_gcscan;
slice->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
@ -185,14 +177,7 @@ 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);
}

View File

@ -56,7 +56,7 @@ KRK_Method(str,__add__) {
bl = them->length;
size_t length = al + bl;
char * chars = KRK_ALLOCATE(char, length + 1);
char * chars = ALLOCATE(char, length + 1);
memcpy(chars, a, al);
memcpy(chars + al, b, bl);
chars[length] = '\0';
@ -102,7 +102,7 @@ KRK_Method(str,__int__) {
KRK_Method(str,__float__) {
METHOD_TAKES_NONE();
#ifndef KRK_NO_FLOAT
return krk_parse_float(AS_CSTRING(argv[0]),AS_STRING(argv[0])->length);
return FLOATING_VAL(strtod(AS_CSTRING(argv[0]),NULL));
#else
return krk_runtimeError(vm.exceptions->valueError, "no float support");
#endif
@ -825,47 +825,17 @@ KRK_Method(str,index) {
}
KRK_Method(str,startswith) {
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);
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));
}
KRK_Method(str,endswith) {
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);
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));
}
/**
@ -892,35 +862,33 @@ KRK_Method(str,__repr__) {
pushStringBuilder(&sb, quote);
for (char * c = AS_CSTRING(argv[0]); c < end; ++c) {
unsigned char ch = *c;
int addSlash = 0;
switch (ch) {
switch (*c) {
/* XXX: Other non-printables should probably be escaped as well. */
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) {
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) {
pushStringBuilder(&sb,'\\');
pushStringBuilder(&sb,'x');
char hex[3];
snprintf(hex, 3, "%02x", (unsigned char)*c);
pushStringBuilder(&sb,hex[0]);
pushStringBuilder(&sb,hex[1]);
continue;
} else {
pushStringBuilder(&sb,*c);
}
break;
}
if (addSlash) krk_pushStringBuilder(&sb,'\\');
krk_pushStringBuilder(&sb,ch);
}
}
pushStringBuilder(&sb, quote);
@ -1082,8 +1050,8 @@ _corrupt:
void krk_pushStringBuilder(struct StringBuilder * sb, char c) {
if (sb->capacity < sb->length + 1) {
size_t old = sb->capacity;
sb->capacity = KRK_GROW_CAPACITY(old);
sb->bytes = KRK_GROW_ARRAY(char, sb->bytes, old, sb->capacity);
sb->capacity = GROW_CAPACITY(old);
sb->bytes = GROW_ARRAY(char, sb->bytes, old, sb->capacity);
}
sb->bytes[sb->length++] = c;
}
@ -1093,9 +1061,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 = KRK_GROW_CAPACITY(old);
sb->capacity = GROW_CAPACITY(old);
}
sb->bytes = KRK_GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
sb->bytes = GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
}
for (size_t i = 0; i < len; ++i) {
sb->bytes[sb->length++] = *(str++);
@ -1103,7 +1071,7 @@ void krk_pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t
}
static void _freeStringBuilder(struct StringBuilder * sb) {
KRK_FREE_ARRAY(char,sb->bytes, sb->capacity);
FREE_ARRAY(char,sb->bytes, sb->capacity);
sb->bytes = NULL;
sb->length = 0;
sb->capacity = 0;
@ -1133,7 +1101,9 @@ int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va
}
/* Bail on exception */
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) break;
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
return 0;
}
++f;
@ -1225,8 +1195,6 @@ 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();
}
@ -1251,7 +1219,6 @@ int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va
}
}
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return 0;
return 1;
}

View File

@ -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) ? KRK_GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = KRK_GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
positionals->capacity = (count == 1) ? GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
}
for (size_t i = 0; i < count; ++i) {
@ -148,8 +148,15 @@ KRK_Method(tuple,__repr__) {
pushStringBuilder(&sb, '(');
for (size_t i = 0; i < self->values.count; ++i) {
if (i) pushStringBuilderStr(&sb, ", ", 2);
if (!krk_pushStringBuilderFormat(&sb, "%R", self->values.values[i])) goto _error;
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 (self->values.count == 1) {
@ -159,11 +166,6 @@ 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__) {
@ -281,6 +283,7 @@ void _createAndBind_tupleClass(void) {
BIND_METHOD(tuple,__hash__);
BIND_METHOD(tuple,__add__);
BIND_METHOD(tuple,__mul__);
krk_defineNative(&tuple->methods, "__str__", FUNC_NAME(tuple,__repr__));
krk_finalizeClass(tuple);
ADD_BASE_CLASS(vm.baseClasses->tupleiteratorClass, "tupleiterator", vm.baseClasses->objectClass);

View File

@ -7,7 +7,6 @@
#include <kuroko/value.h>
#include <kuroko/vm.h>
#include <kuroko/table.h>
#include <kuroko/threads.h>
#include "private.h"
@ -172,8 +171,6 @@ 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);
@ -189,7 +186,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_tableSetExact(&vm.strings, OBJECT_VAL(string), NONE_VAL());
krk_tableSet(&vm.strings, OBJECT_VAL(string), NONE_VAL());
krk_pop();
_release_lock(_stringLock);
return string;
@ -210,7 +207,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 KRK_FREE_ARRAY */
free(chars); /* This string isn't owned by us yet, so free, not FREE_ARRAY */
_release_lock(_stringLock);
return interned;
}
@ -229,7 +226,7 @@ KrkString * krk_copyString(const char * chars, size_t length) {
_release_lock(_stringLock);
return interned;
}
char * heapChars = KRK_ALLOCATE(char, length + 1);
char * heapChars = ALLOCATE(char, length + 1);
memcpy(heapChars, chars ? chars : "", length);
heapChars[length] = '\0';
KrkString * result = allocateString(heapChars, length, hash);
@ -242,7 +239,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) {
KRK_FREE_ARRAY(char, chars, length + 1);
FREE_ARRAY(char, chars, length + 1);
_release_lock(_stringLock);
return interned;
}
@ -255,7 +252,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_tableSetExact(&vm.strings, OBJECT_VAL(string), NONE_VAL());
krk_tableSet(&vm.strings, OBJECT_VAL(string), NONE_VAL());
krk_pop();
_release_lock(_stringLock);
return string;
@ -274,7 +271,6 @@ KrkCodeObject * krk_newCodeObject(void) {
krk_initValueArray(&codeobject->positionalArgNames);
krk_initValueArray(&codeobject->keywordArgNames);
krk_initChunk(&codeobject->chunk);
codeobject->jumpTargets = NONE_VAL();
return codeobject;
}
@ -288,7 +284,7 @@ KrkNative * krk_newNative(NativeFn function, const char * name, int type) {
}
KrkClosure * krk_newClosure(KrkCodeObject * function, KrkValue globals) {
KrkUpvalue ** upvalues = KRK_ALLOCATE(KrkUpvalue*, function->upvalueCount);
KrkUpvalue ** upvalues = ALLOCATE(KrkUpvalue*, function->upvalueCount);
for (size_t i = 0; i < function->upvalueCount; ++i) {
upvalues[i] = NULL;
}
@ -359,7 +355,7 @@ KrkTuple * krk_newTuple(size_t length) {
krk_initValueArray(&tuple->values);
krk_push(OBJECT_VAL(tuple));
tuple->values.capacity = length;
tuple->values.values = KRK_GROW_ARRAY(KrkValue,NULL,0,length);
tuple->values.values = GROW_ARRAY(KrkValue,NULL,0,length);
krk_pop();
return tuple;
}
@ -369,7 +365,7 @@ KrkBytes * krk_newBytes(size_t length, uint8_t * source) {
bytes->length = length;
bytes->bytes = NULL;
krk_push(OBJECT_VAL(bytes));
bytes->bytes = KRK_ALLOCATE(uint8_t, length);
bytes->bytes = ALLOCATE(uint8_t, length);
bytes->obj.hash = -1;
if (source) {
memcpy(bytes->bytes, source, length);

View File

@ -25,20 +25,16 @@ 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

View File

@ -49,7 +49,7 @@ SIMPLE(OP_RAISE_FROM)
SIMPLE(OP_SHIFTLEFT)
JUMP(OP_POP_JUMP_IF_FALSE,+)
SIMPLE(OP_ANNOTATE)
JUMP(OP_FILTER_EXCEPT,+)
SIMPLE(OP_FILTER_EXCEPT)
SIMPLE(OP_BITAND)
SIMPLE(OP_NONE)
SIMPLE(OP_POP)
@ -120,7 +120,3 @@ 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)

View File

@ -23,9 +23,6 @@
/* 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);
@ -92,7 +89,7 @@ KRK_Function(uname) {
#endif
#define AS_Environ(o) (AS_INSTANCE(o))
#define IS_Environ(o) (krk_isInstanceOf(o,os_Environ))
#define IS_Environ(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(Environ)))
#define CURRENT_CTYPE KrkInstance*
static int _setVar(KrkString * key, KrkString * val) {
@ -144,7 +141,7 @@ KRK_Method(Environ,__delitem__) {
static void _loadEnviron(KrkInstance * module) {
/* Create a new class to subclass `dict` */
KrkClass * Environ = krk_makeClass(module, &os_Environ, "_Environ", vm.baseClasses->dictClass);
KrkClass * Environ = krk_makeClass(module, &KRK_BASE_CLASS(Environ), "_Environ", vm.baseClasses->dictClass);
krk_attachNamedObject(&module->fields, "_Environ", (KrkObj*)Environ);
/* Add our set method that should also call dict's set method */
@ -556,7 +553,7 @@ KRK_Function(stat) {
if (result == -1) {
return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
}
KrkInstance * out = krk_newInstance(os_stat_result);
KrkInstance * out = krk_newInstance(KRK_BASE_CLASS(stat_result));
krk_push(OBJECT_VAL(out));
SET(st_dev);
@ -574,7 +571,7 @@ KRK_Function(stat) {
}
#undef SET
#define IS_stat_result(o) (krk_isInstanceOf(o,os_stat_result))
#define IS_stat_result(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(stat_result)))
#define AS_stat_result(o) AS_INSTANCE(o)
#define CURRENT_NAME self
@ -617,7 +614,49 @@ KRK_Method(stat_result,__repr__) {
return krk_pop();
}
KRK_Module(os) {
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_DOC(module, "@brief Provides access to low-level system operations.");
#ifdef _WIN32
@ -830,7 +869,7 @@ KRK_Module(os) {
_loadEnviron(module);
/* Nothing special */
KrkClass * stat_result = krk_makeClass(module, &os_stat_result, "stat_result", vm.baseClasses->objectClass);
KrkClass * stat_result = krk_makeClass(module, &KRK_BASE_CLASS(stat_result), "stat_result", vm.baseClasses->objectClass);
BIND_METHOD(stat_result,__repr__);
krk_finalizeClass(stat_result);
@ -838,6 +877,23 @@ KRK_Module(os) {
"@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
}

View File

@ -1,75 +1,29 @@
/**
* @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>
/**
* @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.
* 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 ).
*/
_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));
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;
}
/**
* @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.
@ -83,7 +37,7 @@ static int extractKwArg(KrkTable * kwargs, KrkString * argName, KrkValue * out,
* @returns 1 on success, 0 on error.
*/
int krk_parseVArgs(
const char * orig_method_name,
const char * _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 */
@ -91,6 +45,11 @@ int krk_parseVArgs(
int required = 1; /**< Parser state, whether required arguments are being collected */
int acceptextrakws = 0; /**< Whether extra keyword args should produce an error (0) or not (1) */
const char * maybeColon = strchr(fmt, ':');
if (maybeColon) {
_method_name = maybeColon + 1;
}
if (*fmt == '.') {
/**
* If the format string starts with `.` then argument processing skips the first argument
@ -168,16 +127,27 @@ int krk_parseVArgs(
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++;
} else if ((required && !hasKw) || (hasKw && extractKwArg(AS_DICT(argv[argc]), krk_copyString(names[oarg],strlen(names[oarg])), &arg, AS_LIST(argv[argc+1])) && required)) {
wasPositional = 1;
} else if ((required && !hasKw) || (hasKw && !krk_tableGet_fast(AS_DICT(argv[argc]), AS_STRING(krk_peek(0)), &arg) && 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, names[oarg]);
krk_runtimeError(vm.exceptions->typeError, "%s() missing required positional argument: '%S'",
_method_name, AS_STRING(krk_peek(0)));
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;
}
@ -188,7 +158,7 @@ int krk_parseVArgs(
* 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));
*out = arg != KWARGS_VAL(0);
}
if (*fmt == '!') {
@ -198,10 +168,7 @@ int krk_parseVArgs(
* 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;
}
if (!matchType(_method_name, type, arg)) goto _error;
}
switch (argtype) {
@ -216,11 +183,11 @@ int krk_parseVArgs(
*/
case 'O': {
KrkObj ** out = va_arg(args, KrkObj**);
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (arg != KWARGS_VAL(0)) {
if (IS_NONE(arg)) {
*out = NULL;
} else if (!IS_OBJECT(arg)) {
raise_TypeError(_method_name, "heap object", arg, names[oarg]);
TYPE_ERROR(heap object,arg);
goto _error;
} else {
*out = AS_OBJECT(arg);
@ -240,7 +207,7 @@ int krk_parseVArgs(
*/
case 'V': {
KrkValue * out = va_arg(args, KrkValue*);
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (arg != KWARGS_VAL(0)) {
*out = arg;
}
break;
@ -260,15 +227,15 @@ int krk_parseVArgs(
fmt++;
size = va_arg(args, size_t*);
}
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (IS_NONE(arg)) {
if (arg != KWARGS_VAL(0)) {
if (arg == NONE_VAL()) {
*out = NULL;
if (size) *size = 0;
} else if (IS_STRING(arg)) {
*out = AS_CSTRING(arg);
if (size) *size = AS_STRING(arg)->length;
} else {
raise_TypeError(_method_name, "str or None", arg, names[oarg]);
TYPE_ERROR(str or None,arg);
goto _error;
}
}
@ -285,12 +252,12 @@ int krk_parseVArgs(
fmt++;
size = va_arg(args, size_t*);
}
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (arg != KWARGS_VAL(0)) {
if (IS_STRING(arg)) {
*out = AS_CSTRING(arg);
if (size) *size = AS_STRING(arg)->length;
} else {
raise_TypeError(_method_name, "str", arg, names[oarg]);
TYPE_ERROR(str,arg);
goto _error;
}
}
@ -306,7 +273,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 (!krk_valuesSame(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 (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)
@ -325,9 +292,9 @@ int krk_parseVArgs(
*/
case 'C': {
int * out = va_arg(args, int*);
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (arg != KWARGS_VAL(0)) {
if (!IS_STRING(arg) || AS_STRING(arg)->codesLength != 1) {
raise_TypeError(_method_name, "str of length 1", arg, names[oarg]);
TYPE_ERROR(str of length 1,arg);
goto _error;
}
*out = krk_unicodeCodepoint(AS_STRING(arg),0);
@ -341,13 +308,13 @@ int krk_parseVArgs(
*/
case 'f': {
float * out = va_arg(args, float*);
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (arg != KWARGS_VAL(0)) {
if (!IS_FLOATING(arg)) {
KrkClass * type = krk_getType(arg);
krk_push(arg);
if (!krk_bindMethod(type, S("__float__"))) {
krk_pop();
raise_TypeError(_method_name, "float", arg, names[oarg]);
TYPE_ERROR(float,arg);
goto _error;
}
arg = krk_callStack(0);
@ -362,13 +329,13 @@ int krk_parseVArgs(
*/
case 'd': {
double * out = va_arg(args, double*);
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (arg != KWARGS_VAL(0)) {
if (!IS_FLOATING(arg)) {
KrkClass * type = krk_getType(arg);
krk_push(arg);
if (!krk_bindMethod(type, S("__float__"))) {
krk_pop();
raise_TypeError(_method_name, "float", arg, names[oarg]);
TYPE_ERROR(float,arg);
goto _error;
}
arg = krk_callStack(0);
@ -392,7 +359,7 @@ int krk_parseVArgs(
*/
case 'p': {
int * out = va_arg(args, int*);
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (arg != KWARGS_VAL(0)) {
*out = !krk_isFalsey(arg);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _error;
}
@ -405,6 +372,7 @@ int krk_parseVArgs(
}
}
krk_pop();
oarg++;
}
@ -428,15 +396,6 @@ 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;
@ -447,6 +406,7 @@ int krk_parseVArgs(
return 1;
_error:
krk_pop(); /* name of argument with error */
return 0;
}
@ -454,12 +414,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;
}

View File

@ -67,28 +67,3 @@ 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

View File

@ -5,7 +5,6 @@
#include <errno.h>
#include <sys/types.h>
#include <kuroko/kuroko.h>
#include <kuroko/scanner.h>
KrkScanner krk_initScanner(const char * src) {
@ -180,12 +179,6 @@ 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);
}
@ -356,9 +349,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);

View File

@ -4,12 +4,12 @@
#include <kuroko/util.h>
#define KRK_VERSION_MAJOR 1
#define KRK_VERSION_MINOR 5
#define KRK_VERSION_MINOR 4
#define KRK_VERSION_PATCH 0
#define KRK_VERSION_LEVEL 0xa
#define KRK_VERSION_SERIAL 0x1
#define KRK_VERSION_LEVEL 0xf
#define KRK_VERSION_SERIAL 0x0
#define KRK_VERSION_EXTRA_BASE "a1"
#define KRK_VERSION_EXTRA_BASE ""
#ifndef KRK_STATIC_ONLY
#define KRK_VERSION_EXTRA KRK_VERSION_EXTRA_BASE
@ -23,10 +23,6 @@
# 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
@ -77,15 +73,12 @@ 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: {
@ -107,13 +100,13 @@ KRK_Function(getsizeof) {
case KRK_OBJ_CLASS: {
KrkClass * self = AS_CLASS(argv[0]);
mySize += sizeof(KrkClass);
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->methods.capacity;
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->subclasses.capacity;
mySize += sizeof(KrkTableEntry) * self->methods.capacity;
mySize += sizeof(KrkTableEntry) * self->subclasses.capacity;
break;
}
case KRK_OBJ_INSTANCE: {
KrkInstance * self = AS_INSTANCE(argv[0]);
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->fields.capacity;
mySize += sizeof(KrkTableEntry) * self->fields.capacity;
KrkClass * type = krk_getType(argv[0]);
mySize += type->allocSize; /* All instance types have an allocSize set */
@ -121,7 +114,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) + sizeof(ssize_t)) * AS_DICT(argv[0])->capacity;
mySize += sizeof(KrkTableEntry) * AS_DICT(argv[0])->capacity;
}
break;
}
@ -208,22 +201,6 @@ KRK_Function(members) {
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()
@ -273,12 +250,8 @@ void krk_module_init_kuroko(void) {
"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(KRK_PATH_SEP));
krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(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("./")));

View File

@ -1,23 +1,4 @@
/**
* @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 <stdio.h>
#include <string.h>
#include <kuroko/kuroko.h>
#include <kuroko/object.h>
@ -33,14 +14,11 @@
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) {
KRK_FREE_ARRAY(KrkTableEntry, table->entries, table->capacity);
KRK_FREE_ARRAY(ssize_t, table->indexes, table->capacity);
FREE_ARRAY(KrkTableEntry, table->entries, table->capacity);
krk_initTable(table);
}
@ -76,7 +54,7 @@ inline int krk_hashValue(KrkValue value, uint32_t *hashOut) {
return 0;
}
if (IS_CLASS(value)) {
*hashOut = (uint32_t)((int)(intptr_t)AS_OBJECT(value));
*hashOut = INTEGER_VAL((int)(intptr_t)AS_OBJECT(value));
return 0;
}
_unhashable:
@ -85,117 +63,106 @@ _unhashable:
return 1;
}
static inline ssize_t krk_tableIndexKeyC(const KrkTableEntry * entries, const ssize_t * indexes, size_t capacity, KrkValue key, int (*comparator)(KrkValue,KrkValue)) {
KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue key) {
uint32_t index;
if (krk_hashValue(key, &index)) return -1;
index &= (capacity - 1);
ssize_t tombstone = -1;
if (krk_hashValue(key, &index)) {
return NULL;
}
index &= (capacity-1);
KrkTableEntry * tombstone = NULL;
for (;;) {
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;
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;
}
index = (index + 1) & (capacity - 1);
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);
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_tableIndexKeyExact(const KrkTableEntry * entries, const ssize_t * indexes, size_t capacity, KrkValue key) {
return krk_tableIndexKeyC(entries,indexes,capacity,key,krk_valuesSame);
#ifdef __TINYC__
int __builtin_clz(unsigned int x) {
int i = 31;
while (!(x & (1 << i)) && i >= 0) i--;
return 31-i;
}
#endif
void krk_tableAdjustCapacity(KrkTable * table, size_t capacity) {
KrkTableEntry * nentries = KRK_ALLOCATE(KrkTableEntry, capacity);
ssize_t * nindexes = KRK_ALLOCATE(ssize_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);
for (size_t i = 0; i < capacity; ++i) {
nindexes[i] = -1;
nentries[i].key = KWARGS_VAL(0);
nentries[i].value = KWARGS_VAL(0);
entries[i].key = KWARGS_VAL(0);
entries[i].value = KWARGS_VAL(0);
}
/* 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++;
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++;
}
/* 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 */
FREE_ARRAY(KrkTableEntry, table->entries, table->capacity);
table->entries = entries;
table->capacity = capacity;
table->used = table->count;
}
int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) {
if (table->used + 1 > table->capacity * TABLE_MAX_LOAD) {
size_t capacity = KRK_GROW_CAPACITY(table->capacity);
if (table->count + 1 > table->capacity * TABLE_MAX_LOAD) {
size_t capacity = GROW_CAPACITY(table->capacity);
krk_tableAdjustCapacity(table, capacity);
}
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];
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;
table->used++;
table->count++;
} else {
entry = &table->entries[table->indexes[index]];
}
entry->value = value;
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;
return isNewKey;
}
int krk_tableSetIfExists(KrkTable * table, KrkValue key, KrkValue value) {
if (table->count == 0) return 0;
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;
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;
return 1;
}
@ -210,69 +177,75 @@ void krk_tableAddAll(KrkTable * from, KrkTable * to) {
int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) {
if (table->count == 0) return 0;
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;
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
if (!entry || IS_KWARGS(entry->key)) {
return 0;
} else {
*value = entry->value;
return 1;
}
}
int krk_tableGet_fast(KrkTable * table, KrkString * str, KrkValue * value) {
if (table->count == 0) return 0;
if (unlikely(table->count == 0)) return 0;
uint32_t index = str->obj.hash & (table->capacity-1);
ssize_t tombstone = -1;
KrkTableEntry * tombstone = NULL;
for (;;) {
if (table->indexes[index] == -1) {
KrkTableEntry * entry = &table->entries[index];
if (entry->key == KWARGS_VAL(0)) {
return 0;
} 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;
} 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;
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;
ssize_t index = krk_tableIndexKey(table->entries, table->indexes, table->capacity, key);
if (index < 0 || table->indexes[index] < 0) return 0;
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
if (!entry || IS_KWARGS(entry->key)) {
return 0;
}
table->count--;
table->entries[table->indexes[index]].key = KWARGS_VAL(0);
table->entries[table->indexes[index]].value = KWARGS_VAL(0);
table->indexes[index] = -2;
entry->key = KWARGS_VAL(1);
entry->value = KWARGS_VAL(0);
return 1;
}
int krk_tableDeleteExact(KrkTable * table, KrkValue key) {
if (table->count == 0) return 0;
ssize_t index = krk_tableIndexKeyExact(table->entries, table->indexes, table->capacity, key);
if (index < 0 || table->indexes[index] < 0) return 0;
KrkTableEntry * entry = krk_findEntryExact(table->entries, table->capacity, key);
if (!entry || IS_KWARGS(entry->key)) {
return 0;
}
table->count--;
table->entries[table->indexes[index]].key = KWARGS_VAL(0);
table->entries[table->indexes[index]].value = KWARGS_VAL(0);
table->indexes[index] = -2;
entry->key = KWARGS_VAL(1);
entry->value = KWARGS_VAL(0);
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);
ssize_t tombstone = -1;
uint32_t index = hash & (table->capacity-1);
KrkTableEntry * tombstone = NULL;
for (;;) {
if (table->indexes[index] == -1) {
KrkTableEntry * entry = &table->entries[index];
if (entry->key == KWARGS_VAL(0)) {
return NULL;
} 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);
} 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);
}
index = (index + 1) & (table->capacity - 1);
index = (index + 1) & (table->capacity-1);
}
}

View File

@ -4,7 +4,6 @@
#ifndef KRK_DISABLE_THREADS
#include <kuroko/util.h>
#include <kuroko/threads.h>
#include <unistd.h>
#include <pthread.h>
@ -37,7 +36,6 @@ struct Thread {
pid_t tid;
unsigned int started:1;
unsigned int alive:1;
unsigned int maxrec;
};
/**
@ -63,13 +61,11 @@ 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.maximumCallDepth = self->maxrec;
krk_currentThread.frames = calloc(krk_currentThread.maximumCallDepth,sizeof(KrkCallFrame));
krk_currentThread.frames = calloc(vm.maximumCallDepth,sizeof(KrkCallFrame));
vm.globalFlags |= KRK_GLOBAL_THREADS;
_obtain_lock(_threadLock);
if (vm.threads->next) {
@ -79,6 +75,7 @@ static void * _startthread(void * _threadObj) {
_release_lock(_threadLock);
/* Get our run function */
struct Thread * self = _threadObj;
self->threadState = &krk_currentThread;
self->tid = gettid();
@ -107,7 +104,7 @@ static void * _startthread(void * _threadObj) {
}
_release_lock(_threadLock);
KRK_FREE_ARRAY(size_t, krk_currentThread.stack, krk_currentThread.stackSize);
FREE_ARRAY(size_t, krk_currentThread.stack, krk_currentThread.stackSize);
free(krk_currentThread.frames);
return NULL;
@ -129,15 +126,13 @@ KRK_Method(Thread,join) {
}
KRK_Method(Thread,start) {
unsigned int maxrec = krk_currentThread.maximumCallDepth;
if (!krk_parseArgs(".|I", (const char*[]){"maxrec"}, &maxrec)) return NONE_VAL();
METHOD_TAKES_NONE();
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];

56
src/time.c Normal file
View File

@ -0,0 +1,56 @@
#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.");
}

View File

@ -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 = KRK_GROW_CAPACITY(old);
array->values = KRK_GROW_ARRAY(KrkValue, array->values, old, array->capacity);
array->capacity = GROW_CAPACITY(old);
array->values = GROW_ARRAY(KrkValue, array->values, old, array->capacity);
}
array->values[array->count] = value;
@ -26,10 +26,131 @@ void krk_writeValueArray(KrkValueArray * array, KrkValue value) {
}
void krk_freeValueArray(KrkValueArray * array) {
KRK_FREE_ARRAY(KrkValue, array->values, array->capacity);
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:
#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;
}
}
}
/**
* 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)) {
@ -62,7 +183,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 krk_valuesSame(a,b);
return a == b;
case KRK_VAL_OBJECT:
default:
return _krk_method_equivalence(a,b);
@ -92,9 +213,9 @@ static inline int _krk_diff_type_equivalence(uint16_t val_a, uint16_t val_b, Krk
return _krk_method_equivalence(a,b);
}
_hot
__attribute__((hot))
int krk_valuesSameOrEqual(KrkValue a, KrkValue b) {
if (krk_valuesSame(a,b)) return 1;
if (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)
@ -102,7 +223,7 @@ int krk_valuesSameOrEqual(KrkValue a, KrkValue b) {
: _krk_diff_type_equivalence(val_a, val_b, a, b);
}
_hot
__attribute__((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
View File

@ -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 = "@9";
static const char * COLOR_ALT_FG = "@5";
static const char * COLOR_ALT_BG = "@9";
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_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_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","isinstance","type","tuple","reversed",
"object","exception","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,11 +672,6 @@ 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;
}
@ -2016,27 +2011,29 @@ static int handle_escape(int * this_buf, int * timeout, int c) {
#ifndef _WIN32
static unsigned int _INTR, _EOF;
static struct termios old;
static void set_unbuffered(void) {
static void get_initial_termios(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, TCSADRAIN, &new);
if (wcwidth(0x3042) != 2) setlocale(LC_CTYPE, "");
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &new);
}
static void set_buffered(void) {
tcsetattr(STDOUT_FILENO, TCSADRAIN, &old);
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &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 */
@ -2432,6 +2429,12 @@ 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();
@ -2439,12 +2442,8 @@ 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 ((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")) {
if (theme && !strcmp(theme,"sunsmoke")) { /* TODO bring back theme tables */
rline_exp_load_colorscheme_sunsmoke();
} else {
rline_exp_load_colorscheme_default();

299
src/vm.c
View File

@ -2,6 +2,7 @@
#include <limits.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
@ -66,6 +67,44 @@ void krk_forceThreadData(void) {
#define krk_currentThread (*_macos_currentThread())
#endif
#if !defined(KRK_NO_TRACING) && !defined(__EMSCRIPTEN__) && !defined(KRK_NO_CALLGRIND)
static void _frame_in(KrkCallFrame * frame) {
clock_gettime(CLOCK_MONOTONIC, &frame->in_time);
}
static void _frame_out(KrkCallFrame * frame) {
if (frame->closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_IS_GENERATOR) return;
KrkCallFrame * caller = krk_currentThread.frameCount > 1 ? &krk_currentThread.frames[krk_currentThread.frameCount-2] : NULL;
struct timespec outTime, diff;
clock_gettime(CLOCK_MONOTONIC, &outTime);
diff.tv_sec = outTime.tv_sec - frame->in_time.tv_sec;
diff.tv_nsec = outTime.tv_nsec - frame->in_time.tv_nsec;
if (diff.tv_nsec < 0) {
diff.tv_sec--;
diff.tv_nsec += 1000000000L;
}
fprintf(vm.callgrindFile, "%s %s@%p %d %s %s@%p %d %lld.%.9ld\n",
caller ? (caller->closure->function->chunk.filename->chars) : "stdin",
caller ? (caller->closure->function->qualname ? caller->closure->function->qualname->chars : caller->closure->function->name->chars) : "(root)",
caller ? ((void*)caller->closure->function) : NULL,
caller ? ((int)krk_lineNumber(&caller->closure->function->chunk, caller->ip - caller->closure->function->chunk.code)) : 1,
frame->closure->function->chunk.filename->chars,
frame->closure->function->qualname ? frame->closure->function->qualname->chars : frame->closure->function->name->chars,
(void*)frame->closure->function,
(int)krk_lineNumber(&frame->closure->function->chunk, 0),
(long long)diff.tv_sec, diff.tv_nsec);
}
# define FRAME_IN(frame) if (unlikely(vm.globalFlags & KRK_GLOBAL_CALLGRIND)) { _frame_in(frame); }
# define FRAME_OUT(frame) if (unlikely(vm.globalFlags & KRK_GLOBAL_CALLGRIND)) { _frame_out(frame); }
#else
# define FRAME_IN(frame)
# define FRAME_OUT(frame)
#endif
/*
* In some threading configurations, particular on Windows,
* we can't have executables reference our thread-local thread
@ -94,14 +133,14 @@ void krk_resetStack(void) {
void krk_growStack(void) {
size_t old = krk_currentThread.stackSize;
size_t old_offset = krk_currentThread.stackTop - krk_currentThread.stack;
size_t newsize = KRK_GROW_CAPACITY(old);
size_t newsize = GROW_CAPACITY(old);
if (krk_currentThread.flags & KRK_THREAD_DEFER_STACK_FREE) {
KrkValue * newStack = KRK_GROW_ARRAY(KrkValue, NULL, 0, newsize);
KrkValue * newStack = GROW_ARRAY(KrkValue, NULL, 0, newsize);
memcpy(newStack, krk_currentThread.stack, sizeof(KrkValue) * old);
krk_currentThread.stack = newStack;
krk_currentThread.flags &= ~(KRK_THREAD_DEFER_STACK_FREE);
} else {
krk_currentThread.stack = KRK_GROW_ARRAY(KrkValue, krk_currentThread.stack, old, newsize);
krk_currentThread.stack = GROW_ARRAY(KrkValue, krk_currentThread.stack, old, newsize);
}
krk_currentThread.stackSize = newsize;
krk_currentThread.stackTop = krk_currentThread.stack + old_offset;
@ -185,7 +224,7 @@ KrkClass * krk_makeClass(KrkInstance * module, KrkClass ** _class, const char *
*
* For a class built by managed code, called by type.__new__
*/
_nonnull
__attribute__((nonnull))
void krk_finalizeClass(KrkClass * _class) {
KrkValue tmp;
@ -208,7 +247,7 @@ void krk_finalizeClass(KrkClass * _class) {
*entry->method = NULL;
KrkClass * _base = _class;
while (_base) {
if (krk_tableGet_fast(&_base->methods, AS_STRING(vm.specialMethodNames[entry->index]), &tmp)) break;
if (krk_tableGet(&_base->methods, vm.specialMethodNames[entry->index], &tmp)) break;
_base = _base->base;
}
if (_base && (IS_CLOSURE(tmp) || IS_NATIVE(tmp)) && (!(AS_OBJECT(tmp)->flags & KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD) || entry->index == METHOD_NEW)) {
@ -219,10 +258,6 @@ void krk_finalizeClass(KrkClass * _class) {
if (_class->base && _class->_eq != _class->base->_eq) {
if (_class->_hash == _class->base->_hash) {
_class->_hash = NULL;
KrkValue v;
if (!krk_tableGet_fast(&_class->methods, AS_STRING(vm.specialMethodNames[METHOD_HASH]), &v)) {
krk_tableSet(&_class->methods, vm.specialMethodNames[METHOD_HASH], NONE_VAL());
}
}
}
@ -329,8 +364,8 @@ static int _unpack_args(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) ? KRK_GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = KRK_GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
positionals->capacity = (count == 1) ? GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
}
for (size_t i = 0; i < count; ++i) {
@ -364,7 +399,7 @@ int krk_processComplexArguments(int argCount, KrkValueArray * positionals, KrkTa
krk_runtimeError(vm.exceptions->typeError, "%s(): **expression value is not a dict.", name);
return 0;
}
for (size_t i = 0; i < AS_DICT(value)->used; ++i) {
for (size_t i = 0; i < AS_DICT(value)->capacity; ++i) {
KrkTableEntry * entry = &AS_DICT(value)->entries[i];
if (!IS_KWARGS(entry->key)) {
if (!IS_STRING(entry->key)) {
@ -424,7 +459,7 @@ static inline int _callManaged(KrkClosure * closure, int argCount, int returnDep
/* Store scratch while we adjust; we can not make calls while using these scratch
* registers as they may be clobbered by a nested call to _callManaged. */
krk_currentThread.scratchSpace[0] = myList;
krk_currentThread.scratchSpace[1] = myDict;
krk_currentThread.scratchSpace[1] = myList;
/* Pop three things, including the kwargs count */
krk_pop(); /* dict */
@ -478,7 +513,7 @@ static inline int _callManaged(KrkClosure * closure, int argCount, int returnDep
krk_currentThread.scratchSpace[0] = NONE_VAL();
/* Now place keyword arguments */
for (size_t i = 0; i < keywords->used; ++i) {
for (size_t i = 0; i < keywords->capacity; ++i) {
KrkTableEntry * entry = &keywords->entries[i];
if (!IS_KWARGS(entry->key)) {
KrkValue name = entry->key;
@ -571,7 +606,7 @@ _finishKwarg:
return 2;
}
if (unlikely(krk_currentThread.frameCount == (size_t)krk_currentThread.maximumCallDepth)) {
if (unlikely(krk_currentThread.frameCount == vm.maximumCallDepth)) {
krk_runtimeError(vm.exceptions->baseException, "maximum recursion depth exceeded");
goto _errorAfterKeywords;
}
@ -583,6 +618,7 @@ _finishKwarg:
frame->outSlots = frame->slots - returnDepth;
frame->globalsOwner = closure->globalsOwner;
frame->globals = closure->globalsTable;
FRAME_IN(frame);
return 1;
_errorDuringPositionals:
@ -614,7 +650,7 @@ inline KrkValue krk_callNativeOnStack(size_t argCount, const KrkValue *stackArgs
KrkValue result = native(argCount, stackArgs, hasKw);
if (unlikely(krk_currentThread.stack != stackBefore)) {
KRK_FREE_ARRAY(KrkValue, stackBefore, sizeBefore);
FREE_ARRAY(KrkValue, stackBefore, sizeBefore);
}
krk_currentThread.flags &= ~(KRK_THREAD_DEFER_STACK_FREE);
@ -650,17 +686,12 @@ static inline int _callNative(KrkNative* callee, int argCount, int returnDepth)
/* Write the dict into the list */
krk_writeValueArray(AS_LIST(myList), myDict);
/* Also add a list for storing references that get removed from the kwargs dict during mutation. */
KrkValue refList = krk_list_of(0,NULL,0);
krk_push(refList);
krk_writeValueArray(AS_LIST(myList), refList);
/* Reduce the stack to just the list */
krk_currentThread.stack[stackOffsetAfterCall] = myList;
krk_currentThread.stackTop = &krk_currentThread.stack[stackOffsetAfterCall+1];
/* Call with list as arguments */
result = native(AS_LIST(myList)->count-2, AS_LIST(myList)->values, 1);
result = native(AS_LIST(myList)->count-1, AS_LIST(myList)->values, 1);
} else {
result = krk_callNativeOnStack(argCount, krk_currentThread.stackTop - argCount, 0, native);
}
@ -861,8 +892,13 @@ int krk_isFalsey(KrkValue value) {
}
void krk_setMaximumRecursionDepth(size_t maxDepth) {
krk_currentThread.maximumCallDepth = maxDepth;
krk_currentThread.frames = realloc(krk_currentThread.frames, maxDepth * sizeof(KrkCallFrame));
vm.maximumCallDepth = maxDepth;
KrkThreadState * thread = vm.threads;
while (thread) {
thread->frames = realloc(thread->frames, maxDepth * sizeof(KrkCallFrame));
thread = thread->next;
}
}
void krk_initVM(int flags) {
@ -871,11 +907,11 @@ void krk_initVM(int flags) {
#endif
vm.globalFlags = flags & 0xFF00;
vm.maximumCallDepth = KRK_CALL_FRAMES_MAX;
/* Reset current thread */
krk_resetStack();
krk_currentThread.maximumCallDepth = KRK_CALL_FRAMES_MAX;
krk_currentThread.frames = calloc(krk_currentThread.maximumCallDepth,sizeof(KrkCallFrame));
krk_currentThread.frames = calloc(vm.maximumCallDepth,sizeof(KrkCallFrame));
krk_currentThread.flags = flags & 0x00FF;
krk_currentThread.module = NULL;
vm.threads = &krk_currentThread;
@ -932,16 +968,19 @@ void krk_initVM(int flags) {
if (!(vm.globalFlags & KRK_GLOBAL_NO_DEFAULT_MODULES)) {
#ifndef KRK_NO_SYSTEM_MODULES
krk_module_init_kuroko();
krk_module_init_gc();
krk_module_init_time();
krk_module_init_os();
krk_module_init_fileio();
#endif
#ifndef KRK_DISABLE_DEBUG
krk_module_init_dis();
#endif
#ifndef KRK_DISABLE_THREADS
krk_module_init_threading();
#endif
}
#ifndef KRK_DISABLE_DEBUG
krk_debug_init();
#endif
/* The VM is now ready to start executing code. */
krk_resetStack();
@ -964,11 +1003,11 @@ void krk_freeVM(void) {
while (krk_currentThread.next) {
KrkThreadState * thread = krk_currentThread.next;
krk_currentThread.next = thread->next;
KRK_FREE_ARRAY(size_t, thread->stack, thread->stackSize);
FREE_ARRAY(size_t, thread->stack, thread->stackSize);
free(thread->frames);
}
KRK_FREE_ARRAY(size_t, krk_currentThread.stack, krk_currentThread.stackSize);
FREE_ARRAY(size_t, krk_currentThread.stack, krk_currentThread.stackSize);
memset(&krk_vm,0,sizeof(krk_vm));
free(krk_currentThread.frames);
memset(&krk_currentThread,0,sizeof(KrkThreadState));
@ -1092,9 +1131,7 @@ static int handleException(void) {
stackOffset >= exitSlot &&
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_PUSH_TRY) &&
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_PUSH_WITH) &&
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_FILTER_EXCEPT) &&
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_RAISE) &&
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_END_FINALLY)
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_FILTER_EXCEPT)
; stackOffset--);
if (stackOffset < exitSlot) {
if (exitSlot == 0) {
@ -1193,7 +1230,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr
/* Try .../path/__init__.krk */
krk_push(OBJECT_VAL(path));
krk_addObjects();
krk_push(OBJECT_VAL(S(KRK_PATH_SEP "__init__.krk")));
krk_push(OBJECT_VAL(S(PATH_SEP "__init__.krk")));
krk_addObjects();
fileName = AS_CSTRING(krk_peek(0));
if (stat(fileName,&statbuf) == 0) {
@ -1203,7 +1240,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr
/* Convert back to .-formatted */
krk_push(krk_valueGetAttribute(OBJECT_VAL(path), "replace"));
krk_push(OBJECT_VAL(S(KRK_PATH_SEP)));
krk_push(OBJECT_VAL(S(PATH_SEP)));
krk_push(OBJECT_VAL(S(".")));
krk_push(krk_callStack(2));
KrkValue packageName = krk_peek(0);
@ -1281,12 +1318,11 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr
krk_runfile(fileName,fileName);
*moduleOut = OBJECT_VAL(krk_currentThread.module);
krk_currentThread.module = enclosing;
if (!IS_OBJECT(*moduleOut) || (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
if (!IS_OBJECT(*moduleOut)) {
if (!(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
krk_runtimeError(vm.exceptions->importError,
"Failed to load module '%S' from '%s'", runAs, fileName);
}
krk_tableDelete(&vm.modules, OBJECT_VAL(runAs));
return 0;
}
@ -1297,7 +1333,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr
#ifndef KRK_STATIC_ONLY
_sharedObject: (void)0;
krk_dlRefType dlRef = krk_dlOpen(fileName);
dlRefType dlRef = dlOpen(fileName);
if (!dlRef) {
*moduleOut = NONE_VAL();
krk_runtimeError(vm.exceptions->importError,
@ -1317,11 +1353,11 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr
char * handlerName = AS_CSTRING(krk_peek(0));
KrkValue (*moduleOnLoad)(KrkString * name);
krk_dlSymType out = krk_dlSym(dlRef, handlerName);
dlSymType out = dlSym(dlRef, handlerName);
memcpy(&moduleOnLoad,&out,sizeof(out));
if (!moduleOnLoad) {
krk_dlClose(dlRef);
dlClose(dlRef);
*moduleOut = NONE_VAL();
krk_runtimeError(vm.exceptions->importError,
"Failed to run module initialization method '%s' from shared object '%s'",
@ -1333,7 +1369,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr
*moduleOut = moduleOnLoad(runAs);
if (!krk_isInstanceOf(*moduleOut, vm.baseClasses->moduleClass)) {
krk_dlClose(dlRef);
dlClose(dlRef);
krk_runtimeError(vm.exceptions->importError,
"Failed to load module '%S' from '%s'", runAs, fileName);
return 0;
@ -1363,7 +1399,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr
if (runAs == S("__main__")) {
/* Then let's use 'path' instead, and replace all the /'s with .'s... */
krk_push(krk_valueGetAttribute(OBJECT_VAL(path), "replace"));
krk_push(OBJECT_VAL(S(KRK_PATH_SEP)));
krk_push(OBJECT_VAL(S(PATH_SEP)));
krk_push(OBJECT_VAL(S(".")));
krk_push(krk_callStack(2));
} else {
@ -1477,7 +1513,7 @@ int krk_importModule(KrkString * name, KrkString * runAs) {
pushStringBuilderStr(&sb, &name->chars[dots], name->length - dots);
}
krk_push(finishStringBuilder(&sb));
krk_push(OBJECT_VAL(finishStringBuilder(&sb)));
/* Now to try to import the fully qualified module path */
if (krk_importModule(AS_STRING(krk_peek(0)), AS_STRING(krk_peek(0)))) {
@ -1557,7 +1593,7 @@ int krk_importModule(KrkString * name, KrkString * runAs) {
krk_currentThread.stack[argBase-1] = krk_pop();
/* Now concatenate forward slash... */
krk_push(krk_currentThread.stack[argBase+1]); /* Slash path */
krk_push(OBJECT_VAL(S(KRK_PATH_SEP)));
krk_push(OBJECT_VAL(S(PATH_SEP)));
krk_addObjects();
krk_currentThread.stack[argBase+1] = krk_pop();
/* And now for the dot... */
@ -1613,7 +1649,7 @@ static void clearCache(KrkClass * type) {
type->cacheIndex = 0;
for (size_t i = 0; i < type->subclasses.capacity; ++i) {
KrkTableEntry * entry = &type->subclasses.entries[i];
if (krk_valuesSame(entry->key, KWARGS_VAL(0))) continue;
if (entry->key == KWARGS_VAL(0)) continue;
clearCache(AS_CLASS(entry->key));
}
}
@ -1751,12 +1787,10 @@ static int valueGetProperty(KrkString * name) {
krk_currentThread.stackTop[-2] = krk_currentThread.stackTop[-1];
krk_currentThread.stackTop--;
return 1;
case 1: {
KrkValue o = OBJECT_VAL(krk_newBoundMethod(krk_currentThread.stackTop[-2], AS_OBJECT(krk_currentThread.stackTop[-1])));
krk_currentThread.stackTop[-2] = o;
case 1:
krk_currentThread.stackTop[-2] = OBJECT_VAL(krk_newBoundMethod(krk_currentThread.stackTop[-2], AS_OBJECT(krk_currentThread.stackTop[-1])));
krk_currentThread.stackTop--;
return 1;
}
default:
return 0;
}
@ -1874,19 +1908,16 @@ static int valueSetProperty(KrkString * name) {
return 1;
}
if (IS_INSTANCE(owner)) {
KrkValue o = setAttr_wrapper(owner,type,&AS_INSTANCE(owner)->fields, name, value);
krk_currentThread.stackTop[-1] = o;
krk_currentThread.stackTop[-1] = setAttr_wrapper(owner,type,&AS_INSTANCE(owner)->fields, name, value);
} else if (IS_CLASS(owner)) {
KrkValue o = setAttr_wrapper(owner,type,&AS_CLASS(owner)->methods, name, value);
krk_currentThread.stackTop[-1] = o;
krk_currentThread.stackTop[-1] = setAttr_wrapper(owner,type,&AS_CLASS(owner)->methods, name, value);
if (name->length > 1 && name->chars[0] == '_' && name->chars[1] == '_') {
krk_finalizeClass(AS_CLASS(owner));
} else {
clearCache(AS_CLASS(owner));
}
} else if (IS_CLOSURE(owner)) {
KrkValue o = setAttr_wrapper(owner,type,&AS_CLOSURE(owner)->fields, name, value);
krk_currentThread.stackTop[-1] = o;
krk_currentThread.stackTop[-1] = setAttr_wrapper(owner,type,&AS_CLOSURE(owner)->fields, name, value);
} else {
if (_setDescriptor(owner,type,name,value)) {
krk_swap(1);
@ -2082,7 +2113,7 @@ static KrkValue run(void) {
while (1) {
if (unlikely(krk_currentThread.flags & (KRK_THREAD_ENABLE_TRACING | KRK_THREAD_SINGLE_STEP | KRK_THREAD_SIGNALLED))) {
#if !defined(KRK_NO_TRACING) && !defined(KRK_DISABLE_DEBUG)
#ifndef KRK_NO_TRACING
if (krk_currentThread.flags & KRK_THREAD_ENABLE_TRACING) {
krk_debug_dumpStack(stderr, frame);
krk_disassembleInstruction(stderr, frame->closure->function,
@ -2111,17 +2142,16 @@ _resumeHook: (void)0;
unsigned int OPERAND = 0;
/* Only GCC lets us put these on empty statements; just hope clang doesn't start complaining */
#if defined(__GNUC__) && !defined(__clang__)
#ifndef __clang__
# define FALLTHROUGH __attribute__((fallthrough));
#else
# define FALLTHROUGH
#endif
#define TWO_BYTE_OPERAND { OPERAND = OPERAND | (frame->ip[0] << 8) | frame->ip[1]; frame->ip += 2; }
#define TWO_BYTE_OPERAND { OPERAND = (frame->ip[0] << 8) | frame->ip[1]; frame->ip += 2; }
#define THREE_BYTE_OPERAND { OPERAND = (frame->ip[0] << 16) | (frame->ip[1] << 8); frame->ip += 2; } FALLTHROUGH
#define ONE_BYTE_OPERAND { OPERAND = (OPERAND & ~0xFF) | READ_BYTE(); }
_switchEntry: (void)0;
switch (opcode) {
case OP_CLEANUP_WITH: {
/* Top of stack is a HANDLER that should have had something loaded into it if it was still valid */
@ -2131,7 +2161,6 @@ _switchEntry: (void)0;
KrkClass * type = krk_getType(contextManager);
krk_push(contextManager);
if (AS_HANDLER_TYPE(handler) == OP_RAISE) {
krk_currentThread.stackTop[-2] = HANDLER_VAL(OP_CLEANUP_WITH,AS_HANDLER_TARGET(krk_peek(1)));
krk_push(OBJECT_VAL(krk_getType(exceptionObject)));
krk_push(exceptionObject);
KrkValue tracebackEntries = NONE_VAL();
@ -2164,6 +2193,7 @@ _switchEntry: (void)0;
case OP_RETURN: {
_finishReturn: (void)0;
KrkValue result = krk_pop();
closeUpvalues(frame->slots);
/* See if this frame had a thing */
int stackOffset;
for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1);
@ -2173,14 +2203,13 @@ _finishReturn: (void)0;
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_FILTER_EXCEPT)
; stackOffset--);
if (stackOffset >= (int)frame->slots) {
closeUpvalues(stackOffset);
krk_currentThread.stackTop = &krk_currentThread.stack[stackOffset + 1];
frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(krk_peek(0));
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_RETURN,AS_HANDLER_TARGET(krk_peek(0)));
krk_currentThread.stackTop[-2] = result;
break;
}
closeUpvalues(frame->slots);
FRAME_OUT(frame);
krk_currentThread.frameCount--;
if (krk_currentThread.frameCount == 0) {
krk_pop();
@ -2224,8 +2253,7 @@ _finishReturn: (void)0;
case OP_TRUE: krk_push(BOOLEAN_VAL(1)); break;
case OP_FALSE: krk_push(BOOLEAN_VAL(0)); break;
case OP_UNSET: krk_push(KWARGS_VAL(0)); break;
case OP_NOT: krk_push(BOOLEAN_VAL(krk_isFalsey(krk_peek(0)))); /* fallthrough */
case OP_SWAP_POP: krk_swap(1); /* fallthrough */
case OP_NOT: krk_currentThread.stackTop[-1] = BOOLEAN_VAL(krk_isFalsey(krk_peek(0))); break;
case OP_POP: krk_pop(); break;
case OP_INPLACE_ADD: INPLACE_BINARY_OP(add)
@ -2283,6 +2311,33 @@ _finishReturn: (void)0;
case OP_SWAP:
krk_swap(1);
break;
case OP_FILTER_EXCEPT: {
int isMatch = 0;
if (AS_HANDLER_TYPE(krk_peek(1)) == OP_RETURN) {
isMatch = 0;
} else if (AS_HANDLER_TYPE(krk_peek(1)) == OP_END_FINALLY) {
isMatch = 0;
} else if (AS_HANDLER_TYPE(krk_peek(1)) == OP_EXIT_LOOP) {
isMatch = 0;
} else if (IS_CLASS(krk_peek(0)) && krk_isInstanceOf(krk_peek(2), AS_CLASS(krk_peek(0)))) {
isMatch = 1;
} else if (IS_TUPLE(krk_peek(0))) {
for (size_t i = 0; i < AS_TUPLE(krk_peek(0))->values.count; ++i) {
if (IS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]) && krk_isInstanceOf(krk_peek(2), AS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]))) {
isMatch = 1;
break;
}
}
} else if (IS_NONE(krk_peek(0))) {
isMatch = !IS_NONE(krk_peek(2));
}
if (isMatch) {
krk_currentThread.stackTop[-2] = HANDLER_VAL(OP_FILTER_EXCEPT,AS_HANDLER_TARGET(krk_peek(1)));
}
krk_pop();
krk_push(BOOLEAN_VAL(isMatch));
break;
}
case OP_TRY_ELSE: {
if (IS_HANDLER(krk_peek(0))) {
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_FILTER_EXCEPT,AS_HANDLER_TARGET(krk_peek(0)));
@ -2291,16 +2346,10 @@ _finishReturn: (void)0;
}
case OP_BEGIN_FINALLY: {
if (IS_HANDLER(krk_peek(0))) {
switch (AS_HANDLER_TYPE(krk_peek(0))) {
/* We either entered the @c finally without an exception, or the exception was handled by an @c except */
case OP_PUSH_TRY:
case OP_FILTER_EXCEPT:
if (AS_HANDLER_TYPE(krk_peek(0)) == OP_PUSH_TRY) {
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_BEGIN_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
} else if (AS_HANDLER_TYPE(krk_peek(0)) == OP_FILTER_EXCEPT) {
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_BEGIN_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
break;
/* We entered the @c finally without handling an exception. */
case OP_RAISE:
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_END_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
break;
}
}
break;
@ -2409,40 +2458,18 @@ _finishReturn: (void)0;
break;
}
case OP_OVERLONG_JUMP: {
/* Overlong jumps replace 2-byte operand jump instructions with a zero-operand instruction that
* slowly scans through a dumb table to find the intended jump target and opcode. */
for (size_t i = 0; i < frame->closure->function->overlongJumpsCount; ++i) {
if (frame->closure->function->overlongJumps[i].instructionOffset ==
(size_t)((char*)frame->ip - (char*)frame->closure->function->chunk.code)) {
OPERAND = (int)frame->closure->function->overlongJumps[i].intendedTarget << 16;
opcode = frame->closure->function->overlongJumps[i].originalOpcode;
goto _switchEntry;
}
}
krk_runtimeError(vm.exceptions->valueError, "bad jump");
goto _finishException;
}
case OP_PUSH_BUILD_CLASS: {
KrkValue build_class = NONE_VAL();
krk_tableGet_fast(&vm.builtins->fields, AS_STRING(vm.specialMethodNames[METHOD_BLDCLS]), &build_class);
krk_push(build_class);
break;
}
/*
* Two-byte operands
*/
case OP_JUMP_IF_FALSE_OR_POP: {
TWO_BYTE_OPERAND;
if (krk_valuesSame(krk_peek(0), BOOLEAN_VAL(0)) || krk_isFalsey(krk_peek(0))) frame->ip += OPERAND;
if (krk_peek(0) == BOOLEAN_VAL(0) || krk_isFalsey(krk_peek(0))) frame->ip += OPERAND;
else krk_pop();
break;
}
case OP_POP_JUMP_IF_FALSE: {
TWO_BYTE_OPERAND;
if (krk_valuesSame(krk_peek(0), BOOLEAN_VAL(0)) || krk_isFalsey(krk_peek(0))) frame->ip += OPERAND;
if (krk_peek(0) == BOOLEAN_VAL(0) || krk_isFalsey(krk_peek(0))) frame->ip += OPERAND;
krk_pop();
break;
}
@ -2530,7 +2557,7 @@ _finishReturn: (void)0;
krk_push(iter);
krk_push(krk_callStack(0));
/* krk_valuesSame() */
if (krk_valuesSame(iter, krk_peek(0))) frame->ip += OPERAND;
if (iter == krk_peek(0)) frame->ip += OPERAND;
break;
}
case OP_LOOP_ITER: {
@ -2538,55 +2565,12 @@ _finishReturn: (void)0;
KrkValue iter = krk_peek(0);
krk_push(iter);
krk_push(krk_callStack(0));
if (!krk_valuesSame(iter, krk_peek(0))) frame->ip -= OPERAND;
if (iter != krk_peek(0)) frame->ip -= OPERAND;
break;
}
case OP_TEST_ARG: {
TWO_BYTE_OPERAND;
if (!krk_valuesSame(krk_pop(), KWARGS_VAL(0))) frame->ip += OPERAND;
break;
}
case OP_FILTER_EXCEPT: {
TWO_BYTE_OPERAND;
/* "Pop exception to match with and jump if not a match" */
int isMatch = 0;
if (IS_CLASS(krk_peek(0)) && krk_isInstanceOf(krk_peek(2), AS_CLASS(krk_peek(0)))) {
isMatch = 1;
} else if (IS_TUPLE(krk_peek(0))) {
for (size_t i = 0; i < AS_TUPLE(krk_peek(0))->values.count; ++i) {
if (IS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]) && krk_isInstanceOf(krk_peek(2), AS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]))) {
isMatch = 1;
break;
}
}
} else if (IS_NONE(krk_peek(0))) {
isMatch = !IS_NONE(krk_peek(2));
}
if (isMatch) {
/* If exception matched, set handler state. */
krk_currentThread.stackTop[-2] = HANDLER_VAL(OP_FILTER_EXCEPT,AS_HANDLER_TARGET(krk_peek(1)));
} else {
/* If exception did not match, jump to next 'except' or 'finally' */
frame->ip += OPERAND;
}
krk_pop();
break;
}
case OP_ENTER_EXCEPT: {
TWO_BYTE_OPERAND;
switch (AS_HANDLER_TYPE(krk_peek(0))) {
case OP_RETURN:
case OP_END_FINALLY:
case OP_EXIT_LOOP:
frame->ip += OPERAND;
break;
case OP_RAISE_FROM:
/* Exception happened while in @c finally */
krk_pop(); /* handler */
krk_currentThread.currentException = krk_pop();
krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION;
goto _finishException;
}
if (krk_pop() != KWARGS_VAL(0)) frame->ip += OPERAND;
break;
}
@ -2913,7 +2897,8 @@ _finishReturn: (void)0;
THREE_BYTE_OPERAND;
case OP_EXIT_LOOP: {
ONE_BYTE_OPERAND;
_finishPopBlock: (void)0;
_finishPopBlock:
closeUpvalues(frame->slots + OPERAND);
int stackOffset;
for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1);
stackOffset >= (int)(frame->slots + OPERAND) &&
@ -2924,14 +2909,11 @@ _finishPopBlock: (void)0;
/* Do the handler. */
if (stackOffset >= (int)(frame->slots + OPERAND)) {
closeUpvalues(stackOffset);
uint16_t popTarget = (frame->ip - frame->closure->function->chunk.code);
krk_currentThread.stackTop = &krk_currentThread.stack[stackOffset + 1];
frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(krk_peek(0));
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_EXIT_LOOP, popTarget);
krk_currentThread.stackTop[-2] = INTEGER_VAL(OPERAND);
} else {
closeUpvalues(frame->slots + OPERAND);
}
/* Continue normally */
@ -3163,21 +3145,10 @@ _finishException:
frame = &krk_currentThread.frames[krk_currentThread.frameCount - 1];
frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(krk_peek(0));
/* Stick the exception into the exception slot */
switch (AS_HANDLER_TYPE(krk_currentThread.stackTop[-1])) {
/* An exception happened while handling an exception */
case OP_RAISE:
case OP_FILTER_EXCEPT:
if (AS_HANDLER_TYPE(krk_currentThread.stackTop[-1])== OP_FILTER_EXCEPT) {
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_END_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
break;
/* An exception happened while already in the @c finally block from handling
* another exception. Bail. */
case OP_END_FINALLY:
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_RAISE_FROM,AS_HANDLER_TARGET(krk_peek(0)));
break;
/* First exception in this chain. */
default:
} else {
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_RAISE,AS_HANDLER_TARGET(krk_peek(0)));
break;
}
krk_currentThread.stackTop[-2] = krk_currentThread.currentException;
krk_currentThread.currentException = NONE_VAL();
@ -3216,7 +3187,7 @@ KrkInstance * krk_startModule(const char * name) {
return module;
}
KrkValue krk_interpret(const char * src, const char * fromFile) {
KrkValue krk_interpret(const char * src, char * fromFile) {
KrkCodeObject * function = krk_compile(src, fromFile);
if (!function) {
if (!krk_currentThread.frameCount) handleException();
@ -3233,7 +3204,7 @@ KrkValue krk_interpret(const char * src, const char * fromFile) {
}
#ifndef KRK_NO_FILESYSTEM
KrkValue krk_runfile(const char * fileName, const char * fromFile) {
KrkValue krk_runfile(const char * fileName, char * fromFile) {
FILE * f = fopen(fileName,"r");
if (!f) {
fprintf(stderr, "%s: could not open file '%s': %s\n", "kuroko", fileName, strerror(errno));

View File

@ -1,389 +1,389 @@
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'}
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'}
bad pid
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'}
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'}
Missing expected value
Checking {'eyr': '2024', 'byr': '1964', 'ecl': 'brn', 'iyr': '1976', 'hcl': '#866857', 'hgt': '190cm', 'pid': '562135232'}
Checking {'hcl': '#866857', 'iyr': '1976', 'hgt': '190cm', 'byr': '1964', 'pid': '562135232', 'eyr': '2024', 'ecl': 'brn'}
Bad issue year
Checking {'hgt': '193cm', 'pid': '#6e4342', 'iyr': '2011', 'byr': '1936', 'cid': '296', 'hcl': 'z', 'ecl': '#3b8ed3', 'eyr': '2022'}
Checking {'eyr': '2022', 'hcl': 'z', 'iyr': '2011', 'hgt': '193cm', 'pid': '#6e4342', 'byr': '1936', 'cid': '296', 'ecl': '#3b8ed3'}
bad hair color
Checking {'cid': '154', 'byr': '1985', 'pid': '503255860', 'ecl': 'gry', 'eyr': '2023', 'hcl': '#efcc98', 'iyr': '2014'}
Checking {'ecl': 'gry', 'hcl': '#efcc98', 'iyr': '2014', 'byr': '1985', 'pid': '503255860', 'eyr': '2023', 'cid': '154'}
Missing expected value
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'}
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'}
Bad expire year
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'}
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'}
Bad birth year
Checking {'pid': '47030948', 'hcl': '4946ca', 'iyr': '2019', 'hgt': '189', 'ecl': '#1d136d', 'byr': '2013', 'eyr': '2024', 'cid': '51'}
Checking {'cid': '51', 'hcl': '4946ca', 'iyr': '2019', 'hgt': '189', 'pid': '47030948', 'byr': '2013', 'ecl': '#1d136d', 'eyr': '2024'}
Bad birth year
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'}
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'}
Bad issue year
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Bad expire year
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'}
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'}
bad height in inches: 190
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'}
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'}
Missing expected value
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'}
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'}
Bad birth year
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'}
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'}
Missing expected value
Checking {'cid': '256', 'hcl': '234fc4', 'ecl': 'zzz', 'hgt': '177in', 'eyr': '2027', 'iyr': '2015', 'pid': '159cm', 'byr': '2022'}
Checking {'ecl': 'zzz', 'hcl': '234fc4', 'iyr': '2015', 'hgt': '177in', 'pid': '159cm', 'byr': '2022', 'eyr': '2027', 'cid': '256'}
Bad birth year
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'}
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'}
bad pid
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
Checking {'pid': '047851403', 'byr': '1937', 'hcl': '#cfa07d', 'iyr': '2015', 'hgt': '192cm', 'eyr': '2025'}
Checking {'hcl': '#cfa07d', 'iyr': '2015', 'pid': '047851403', 'byr': '1937', 'hgt': '192cm', 'eyr': '2025'}
Missing expected value
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'}
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'}
Missing expected value
Checking {'iyr': '2012', 'byr': '1991', 'ecl': 'blu', 'hcl': '#341e13', 'hgt': '169cm', 'cid': '156', 'pid': '599766528'}
Checking {'hcl': '#341e13', 'iyr': '2012', 'hgt': '169cm', 'byr': '1991', 'pid': '599766528', 'ecl': 'blu', 'cid': '156'}
Missing expected value
Checking {'byr': '2029', 'hgt': '75cm', 'pid': '319443119', 'iyr': '2001', 'eyr': '2020', 'cid': '306', 'ecl': 'zzz'}
Checking {'ecl': 'zzz', 'iyr': '2001', 'hgt': '75cm', 'byr': '2029', 'pid': '319443119', 'eyr': '2020', 'cid': '306'}
Missing expected value
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'}
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'}
Bad birth year
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'}
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'}
Bad birth year
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'}
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'}
Missing expected value
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'}
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'}
Bad birth year
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
Checking {'ecl': 'xry', 'eyr': '2037', 'byr': '2016', 'iyr': '1994', 'cid': '98', 'pid': '522572315', 'hgt': '158cm', 'hcl': '0ee9d4'}
Checking {'eyr': '2037', 'hcl': '0ee9d4', 'iyr': '1994', 'hgt': '158cm', 'byr': '2016', 'pid': '522572315', 'cid': '98', 'ecl': 'xry'}
Bad birth year
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Bad issue year
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'}
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'}
bad height in cm
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'}
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'}
Bad birth year
Checking {'iyr': '1988', 'hgt': '187', 'hcl': 'z', 'ecl': '#30e67c', 'byr': '2020', 'pid': '225115160', 'eyr': '2037'}
Checking {'hcl': 'z', 'iyr': '1988', 'hgt': '187', 'byr': '2020', 'pid': '225115160', 'ecl': '#30e67c', 'eyr': '2037'}
Bad birth year
Checking {'eyr': '2021', 'iyr': '2011', 'hgt': '188cm', 'ecl': 'hzl', 'byr': '1965', 'pid': '455044780'}
Checking {'iyr': '2011', 'byr': '1965', 'pid': '455044780', 'hgt': '188cm', 'eyr': '2021', 'ecl': 'hzl'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
bad height generally
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
Checking {'ecl': '#6db74f', 'iyr': '1921', 'pid': '442332495', 'byr': '2018', 'hcl': 'z', 'cid': '101', 'eyr': '1949'}
Checking {'eyr': '1949', 'hcl': 'z', 'iyr': '1921', 'pid': '442332495', 'byr': '2018', 'ecl': '#6db74f', 'cid': '101'}
Missing expected value
Checking {'cid': '332', 'byr': '2022', 'ecl': 'blu', 'eyr': '2038', 'iyr': '1939', 'hcl': '518816', 'hgt': '191cm', 'pid': '10107923'}
Checking {'ecl': 'blu', 'hcl': '518816', 'iyr': '1939', 'hgt': '191cm', 'byr': '2022', 'pid': '10107923', 'eyr': '2038', 'cid': '332'}
Bad birth year
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'}
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'}
Bad birth year
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'}
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'}
Missing expected value
Checking {'ecl': 'grn', 'cid': '237', 'hcl': '#8936bb', 'hgt': '183cm', 'eyr': '2028', 'iyr': '2015', 'byr': '1998'}
Checking {'cid': '237', 'hcl': '#8936bb', 'iyr': '2015', 'hgt': '183cm', 'byr': '1998', 'eyr': '2028', 'ecl': 'grn'}
Missing expected value
Checking {'pid': '550427102', 'hgt': '67in', 'byr': '1991', 'ecl': 'gry', 'hcl': '#efcc98'}
Checking {'hcl': '#efcc98', 'pid': '550427102', 'byr': '1991', 'hgt': '67in', 'ecl': 'gry'}
Missing expected value
Checking {'cid': '274', 'hgt': '70cm', 'iyr': '2022', 'eyr': '1961', 'hcl': '00f05b', 'byr': '1948', 'ecl': 'gmt'}
Checking {'ecl': 'gmt', 'hcl': '00f05b', 'iyr': '2022', 'hgt': '70cm', 'byr': '1948', 'cid': '274', 'eyr': '1961'}
Missing expected value
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'}
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'}
Missing expected value
Checking {'iyr': '2010', 'pid': '#4f47c3', 'hgt': '154in', 'cid': '69', 'hcl': 'z', 'byr': '2022', 'ecl': '#e36a65'}
Checking {'hcl': 'z', 'iyr': '2010', 'hgt': '154in', 'pid': '#4f47c3', 'byr': '2022', 'cid': '69', 'ecl': '#e36a65'}
Missing expected value
Checking {'ecl': '#5ff50c', 'pid': '499582878', 'hcl': '#b6652a', 'hgt': '171cm', 'iyr': '2016', 'byr': '1930', 'eyr': '2024'}
Checking {'hcl': '#b6652a', 'iyr': '2016', 'hgt': '171cm', 'pid': '499582878', 'byr': '1930', 'ecl': '#5ff50c', 'eyr': '2024'}
bad eye color
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
bad hair color
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'}
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'}
Missing expected value
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'}
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'}
bad eye color
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'}
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'}
Missing expected value
Checking {'byr': '1980', 'hgt': '171cm', 'eyr': '2021', 'pid': '9435249395', 'ecl': 'oth', 'hcl': '#a97842', 'iyr': '2017'}
Checking {'hcl': '#a97842', 'iyr': '2017', 'hgt': '171cm', 'byr': '1980', 'pid': '9435249395', 'eyr': '2021', 'ecl': 'oth'}
bad pid
Checking {'byr': '2011', 'hcl': '#b6652a', 'eyr': '2039', 'ecl': 'hzl', 'iyr': '1923', 'hgt': '186cm', 'pid': '239188418', 'cid': '93'}
Checking {'cid': '93', 'hcl': '#b6652a', 'iyr': '1923', 'hgt': '186cm', 'byr': '2011', 'pid': '239188418', 'eyr': '2039', 'ecl': 'hzl'}
Bad birth year
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'}
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'}
bad pid
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'}
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'}
Missing expected value
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'}
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'}
Bad birth year
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
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'}
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'}
Missing expected value
Checking {'iyr': '2015', 'pid': '654033544', 'cid': '176', 'hgt': '163cm', 'byr': '1923', 'ecl': 'brn', 'hcl': '#866857'}
Checking {'hcl': '#866857', 'iyr': '2015', 'hgt': '163cm', 'pid': '654033544', 'byr': '1923', 'cid': '176', 'ecl': 'brn'}
Missing expected value
Checking {'hcl': '#623a2f', 'byr': '2013', 'hgt': '76cm', 'ecl': '#5cd4a8', 'iyr': '2007', 'eyr': '2035', 'cid': '128', 'pid': '122621229'}
Checking {'cid': '128', 'hcl': '#623a2f', 'iyr': '2007', 'hgt': '76cm', 'byr': '2013', 'pid': '122621229', 'ecl': '#5cd4a8', 'eyr': '2035'}
Bad birth year
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'}
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'}
bad hair color
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'}
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'}
Bad expire year
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'}
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'}
Missing expected value
Checking {'hgt': '119', 'hcl': '7d1404', 'eyr': '1957', 'pid': '143311761', 'iyr': '2027', 'byr': '1939', 'ecl': '#de1d21'}
Checking {'hcl': '7d1404', 'iyr': '2027', 'hgt': '119', 'pid': '143311761', 'byr': '1939', 'eyr': '1957', 'ecl': '#de1d21'}
Bad issue year
Checking {'hgt': '182cm', 'iyr': '2015', 'ecl': 'blu', 'cid': '205', 'pid': '136552613', 'hcl': '#ceb3a1', 'byr': '1992'}
Checking {'hcl': '#ceb3a1', 'iyr': '2015', 'hgt': '182cm', 'pid': '136552613', 'byr': '1992', 'ecl': 'blu', 'cid': '205'}
Missing expected value
Checking {'ecl': 'blu', 'iyr': '2013', 'cid': '54', 'byr': '1998', 'hcl': 'z', 'hgt': '172cm', 'eyr': '2034', 'pid': '#ec3c3a'}
Checking {'eyr': '2034', 'hcl': 'z', 'iyr': '2013', 'hgt': '172cm', 'byr': '1998', 'pid': '#ec3c3a', 'ecl': 'blu', 'cid': '54'}
Bad expire year
Checking {'byr': '1975', 'ecl': 'blu', 'eyr': '2025', 'hcl': '#623a2f', 'pid': '358585328', 'iyr': '2012'}
Checking {'hcl': '#623a2f', 'iyr': '2012', 'byr': '1975', 'pid': '358585328', 'ecl': 'blu', 'eyr': '2025'}
Missing expected value
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'}
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'}
Missing expected value
Checking {'cid': '262', 'byr': '1956', 'iyr': '2014', 'pid': '860561420', 'hcl': '#888785', 'hgt': '176cm'}
Checking {'hcl': '#888785', 'iyr': '2014', 'byr': '1956', 'pid': '860561420', 'hgt': '176cm', 'cid': '262'}
Missing expected value
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'}
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'}
Missing expected value
Checking {'iyr': '2019', 'hgt': '177cm', 'pid': '516533115', 'cid': '294', 'ecl': 'amb', 'hcl': '#ceb3a1', 'byr': '1922'}
Checking {'hcl': '#ceb3a1', 'iyr': '2019', 'hgt': '177cm', 'pid': '516533115', 'byr': '1922', 'cid': '294', 'ecl': 'amb'}
Missing expected value
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'}
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'}
Bad birth year
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'}
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'}
Missing expected value
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'}
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'}
Bad issue year
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'}
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'}
bad hair color
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'}
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'}
Bad birth year
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'}
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'}
Bad issue year
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'}
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'}
Missing expected value
Checking {'byr': '1953', 'ecl': 'oth', 'iyr': '2013', 'hcl': '#b6652a', 'pid': '442586860'}
Checking {'hcl': '#b6652a', 'iyr': '2013', 'byr': '1953', 'pid': '442586860', 'ecl': 'oth'}
Missing expected value
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'}
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'}
Bad issue year
Checking {'ecl': 'oth', 'hcl': '#602927', 'eyr': '2025', 'iyr': '2013', 'hgt': '151cm', 'byr': '1992', 'pid': '812583062'}
Checking {'hcl': '#602927', 'iyr': '2013', 'hgt': '151cm', 'byr': '1992', 'pid': '812583062', 'ecl': 'oth', 'eyr': '2025'}
count = 194

View File

@ -1,9 +1,9 @@
I am a function.
[42]
{'a': <class 'int'>, 'b': <class 'float'>, 'return': <class 'list'>}
{'self': None, 'anint': <class 'int'>, 'adict': 'dict[str,object]', 'return': None}
{'return': <class 'list'>, 'a': <class 'int'>, 'b': <class 'float'>}
{'return': None, 'anint': <class 'int'>, 'self': None, 'adict': 'dict[str,object]'}
I am a method taking a dict.
None
{'abool': <class 'bool'>, 'astr': <class 'str'>}
{'astr': <class 'str'>, 'abool': <class 'bool'>}
I return a Foo? Amazing!
True

View File

@ -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 as exception:
except:
print(exception.arg)

View File

@ -1,5 +1,5 @@
Positionals: [1, 2, 3, 'a', 'b']
Keywords: {'foo': 'bar', 'biz': 42}
Keywords: {'biz': 42, 'foo': 'bar'}
hi
Positionals: []
Keywords: {}

View File

@ -1,3 +1,3 @@
Call starts here.
a = 1 b = 1
args = [2, 3] kwargs = {'foo': 'bar', 'stuff': 'things'}
args = [2, 3] kwargs = {'stuff': 'things', 'foo': 'bar'}

View File

@ -8,7 +8,7 @@ class Foo():
# This doesn't work because amethod is unbound and needs an instance.
try:
Foo.amethod()
except as exception:
except:
print(exception.arg)
# This works
Foo.amethod(Foo())

View File

@ -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 as exception:
except:
print(exception.arg)

View File

@ -1,18 +0,0 @@
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()

View File

@ -1,6 +0,0 @@
in
in
in
out
out
out

View File

@ -120,7 +120,7 @@ def aMethod(with_,args=None):
try:
aMethod()
except as exception:
except:
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 as exception:
except:
print(exception.arg) # unrecognized keyword arg, from inner method
aMethod(*[1,2])
try:
aMethod(*[1,2,3])
except as exception:
except:
print(exception.arg) # too many arguments

View File

@ -20,7 +20,7 @@ del l[3]
print(l) # [1, 3, 4]
try:
del l[3]
except as exception:
except:
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 as exception:
except:
print(exception.arg) # AttributeError
del o.foo.bar
print(dir(o.foo))
try:
print(o.foo.bar)
except as exception:
except:
print(exception.arg) # AttributeError
del o.foo
del o

View File

@ -1,9 +0,0 @@
try:
try:
raise ValueError()
else:
print("oh no (else should not run)")
finally:
print('finally')
except ValueError:
print("value error caught in outer")

View File

@ -1,2 +0,0 @@
finally
value error caught in outer

View File

@ -1,13 +0,0 @@
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')

View File

@ -1,6 +0,0 @@
hello world
no error
and done
hello world
and done
finished

View File

@ -1,14 +0,0 @@
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')

View File

@ -1,4 +0,0 @@
hello world
this is the finally
caught the zero div error
done

View File

@ -2,7 +2,7 @@ def doTheThing(excp):
try:
try:
raise excp
except (TypeError, ValueError) as exception:
except (TypeError, ValueError):
print("Caught a", repr(exception))
for i in exception.traceback:
let func, instr = i

View File

@ -1,98 +0,0 @@
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())

View File

@ -1,54 +0,0 @@
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")
~~~~~~~~~~^~~~~~~~~

View File

@ -1,38 +0,0 @@
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'),
])

View File

@ -1,27 +0,0 @@
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

View File

@ -1,8 +1,8 @@
hello
foo
1
hello
3
hello: world
foo: bar
foo
1: 2
hello: world
3: 4
foo: bar

View File

@ -4,7 +4,7 @@ class Bar(object):
try:
let b = Bar()
except as exception:
except:
print(exception.arg)
class Foo():
@ -13,6 +13,6 @@ class Foo():
try:
let f = Foo()
except as exception:
except:
print(exception.arg)

View File

@ -7,10 +7,10 @@ if True:
try:
let a, b = range(3)
except as exception:
except:
print(repr(exception))
try:
let a, b, c, d = range(3)
except as exception:
except:
print(repr(exception))

View File

@ -1,2 +1,2 @@
{'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'}}}
{'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/*'}}}

View File

@ -9,22 +9,22 @@ function(1,2,keyword2=5)
try:
function(1,keyword2=5)
except as exception:
except:
print(exception.arg)
try:
function(1,2,positional1=4)
except as exception:
except:
print(exception.arg)
try:
function(1,2,keyword2=None,keyword2=5)
except as exception:
except:
print(exception.arg)
function(1,keyword2=4,positional2="abc")
try:
function(1,keyword2=4,keyword1=5,positional1="nope")
except as exception:
except:
print(exception.arg)

View File

@ -1,13 +0,0 @@
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__

View File

@ -1,4 +0,0 @@
try
NameError("Undefined variable 'inner_error'.")
ZeroDivisionError('integer division by zero')
ValueError()

View File

@ -8,7 +8,7 @@ def testTop():
printPackage(foo)
try:
print(foo.bar, "Fail")
except as exception:
except:
print(repr(exception)) # AttributeError
def testCaching():
@ -33,7 +33,7 @@ def testFromImport():
print(baz.qux)
try:
print(foo, "Fail")
except as exception:
except:
print(repr(exception))
def testRenames():
@ -42,17 +42,17 @@ def testRenames():
print(blah.qux)
try:
print(foo, "Fail")
except as exception:
except:
print(repr(exception))
from foo.bar.baz import qux as thing
print(thing)
try:
print(qux, "Fail")
except as exception:
except:
print(repr(exception))
try:
print(foo.bar, "Fail")
except as exception:
except:
print(repr(exception))
if __name__ == '__main__':

View File

@ -1,18 +0,0 @@
print(float('123431236.632163e-3'))
print(float('123431236.632163e3'))
print(float('123431236.632163e30'))
print(float('123431236.632163e-30'))
print(float('-123431236.632163e-3'))
print(float('-123431236.632163e3'))
print(float('-123431236.632163e30'))
print(float('-123431236.632163e-30'))
print(float('2.1234567'))
print(float('0.1234567'))
print(float('0.001234567'))
print(float('0.00001234567'))
print(float('0.000976562500000000325260651745651330202235840260982513427734375'))
print(float('2.47032822920623272088284396434110686182e-324').__format__('.10000g'))
print(float('2.47032822920623272088284396434110686183e-324').__format__('.10000g'))
print(float('4.99e-324').__format__('.10000g'))

View File

@ -1,16 +0,0 @@
123431.236632163
123431236632.163
1.23431236632163e+38
1.23431236632163e-22
-123431.236632163
-123431236632.163
-1.23431236632163e+38
-1.23431236632163e-22
2.1234567
0.1234567
0.001234567
1.234567e-05
0.0009765625000000004
0
4.940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625e-324
4.940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625e-324

View File

@ -2,7 +2,7 @@ import time
try:
time.sleep()
except as exception:
except:
print("oh no! " + exception.arg)
print("Back from try/except")

View File

@ -1,13 +0,0 @@
import random
def __main__(a,n=50000):
for j in range(n):
a.append(random.random())
a.append(42) # Forces heterogynous sorting in CPython
a.sort()
for j in range(n):
assert(a[j] <= a[j+1])
a.sort(reverse=True)
for j in range(n):
assert(a[j] >= a[j+1])
__main__([])

View File

@ -1,21 +0,0 @@
class R:
def __init__(self, name, department, age):
self.name = name
self.department = department
self.age = age
def __repr__(self):
return f'Record({self.name},{self.department},{self.age})'
def __main__(RS,ds,ages,names):
for i in range(50):
RS.append(R(names[i%5],ds[i%3],ages[i%17]))
print(RS)
RS.sort(key=lambda l: l.age)
print(RS)
RS.sort(key=lambda l: l.department)
print(RS)
RS.sort(key=lambda l: l.age, reverse=True)
print(RS)
__main__([], ['Engineering', 'Sales', 'Management'], [n for n in range(30,47)], ['Bob','Dan','Eric','Sue','Tina'])

View File

@ -1,4 +0,0 @@
[Record(Bob,Engineering,30), Record(Dan,Sales,31), Record(Eric,Management,32), Record(Sue,Engineering,33), Record(Tina,Sales,34), Record(Bob,Management,35), Record(Dan,Engineering,36), Record(Eric,Sales,37), Record(Sue,Management,38), Record(Tina,Engineering,39), Record(Bob,Sales,40), Record(Dan,Management,41), Record(Eric,Engineering,42), Record(Sue,Sales,43), Record(Tina,Management,44), Record(Bob,Engineering,45), Record(Dan,Sales,46), Record(Eric,Management,30), Record(Sue,Engineering,31), Record(Tina,Sales,32), Record(Bob,Management,33), Record(Dan,Engineering,34), Record(Eric,Sales,35), Record(Sue,Management,36), Record(Tina,Engineering,37), Record(Bob,Sales,38), Record(Dan,Management,39), Record(Eric,Engineering,40), Record(Sue,Sales,41), Record(Tina,Management,42), Record(Bob,Engineering,43), Record(Dan,Sales,44), Record(Eric,Management,45), Record(Sue,Engineering,46), Record(Tina,Sales,30), Record(Bob,Management,31), Record(Dan,Engineering,32), Record(Eric,Sales,33), Record(Sue,Management,34), Record(Tina,Engineering,35), Record(Bob,Sales,36), Record(Dan,Management,37), Record(Eric,Engineering,38), Record(Sue,Sales,39), Record(Tina,Management,40), Record(Bob,Engineering,41), Record(Dan,Sales,42), Record(Eric,Management,43), Record(Sue,Engineering,44), Record(Tina,Sales,45)]
[Record(Bob,Engineering,30), Record(Eric,Management,30), Record(Tina,Sales,30), Record(Dan,Sales,31), Record(Sue,Engineering,31), Record(Bob,Management,31), Record(Eric,Management,32), Record(Tina,Sales,32), Record(Dan,Engineering,32), Record(Sue,Engineering,33), Record(Bob,Management,33), Record(Eric,Sales,33), Record(Tina,Sales,34), Record(Dan,Engineering,34), Record(Sue,Management,34), Record(Bob,Management,35), Record(Eric,Sales,35), Record(Tina,Engineering,35), Record(Dan,Engineering,36), Record(Sue,Management,36), Record(Bob,Sales,36), Record(Eric,Sales,37), Record(Tina,Engineering,37), Record(Dan,Management,37), Record(Sue,Management,38), Record(Bob,Sales,38), Record(Eric,Engineering,38), Record(Tina,Engineering,39), Record(Dan,Management,39), Record(Sue,Sales,39), Record(Bob,Sales,40), Record(Eric,Engineering,40), Record(Tina,Management,40), Record(Dan,Management,41), Record(Sue,Sales,41), Record(Bob,Engineering,41), Record(Eric,Engineering,42), Record(Tina,Management,42), Record(Dan,Sales,42), Record(Sue,Sales,43), Record(Bob,Engineering,43), Record(Eric,Management,43), Record(Tina,Management,44), Record(Dan,Sales,44), Record(Sue,Engineering,44), Record(Bob,Engineering,45), Record(Eric,Management,45), Record(Tina,Sales,45), Record(Dan,Sales,46), Record(Sue,Engineering,46)]
[Record(Bob,Engineering,30), Record(Sue,Engineering,31), Record(Dan,Engineering,32), Record(Sue,Engineering,33), Record(Dan,Engineering,34), Record(Tina,Engineering,35), Record(Dan,Engineering,36), Record(Tina,Engineering,37), Record(Eric,Engineering,38), Record(Tina,Engineering,39), Record(Eric,Engineering,40), Record(Bob,Engineering,41), Record(Eric,Engineering,42), Record(Bob,Engineering,43), Record(Sue,Engineering,44), Record(Bob,Engineering,45), Record(Sue,Engineering,46), Record(Eric,Management,30), Record(Bob,Management,31), Record(Eric,Management,32), Record(Bob,Management,33), Record(Sue,Management,34), Record(Bob,Management,35), Record(Sue,Management,36), Record(Dan,Management,37), Record(Sue,Management,38), Record(Dan,Management,39), Record(Tina,Management,40), Record(Dan,Management,41), Record(Tina,Management,42), Record(Eric,Management,43), Record(Tina,Management,44), Record(Eric,Management,45), Record(Tina,Sales,30), Record(Dan,Sales,31), Record(Tina,Sales,32), Record(Eric,Sales,33), Record(Tina,Sales,34), Record(Eric,Sales,35), Record(Bob,Sales,36), Record(Eric,Sales,37), Record(Bob,Sales,38), Record(Sue,Sales,39), Record(Bob,Sales,40), Record(Sue,Sales,41), Record(Dan,Sales,42), Record(Sue,Sales,43), Record(Dan,Sales,44), Record(Tina,Sales,45), Record(Dan,Sales,46)]
[Record(Sue,Engineering,46), Record(Dan,Sales,46), Record(Bob,Engineering,45), Record(Eric,Management,45), Record(Tina,Sales,45), Record(Sue,Engineering,44), Record(Tina,Management,44), Record(Dan,Sales,44), Record(Bob,Engineering,43), Record(Eric,Management,43), Record(Sue,Sales,43), Record(Eric,Engineering,42), Record(Tina,Management,42), Record(Dan,Sales,42), Record(Bob,Engineering,41), Record(Dan,Management,41), Record(Sue,Sales,41), Record(Eric,Engineering,40), Record(Tina,Management,40), Record(Bob,Sales,40), Record(Tina,Engineering,39), Record(Dan,Management,39), Record(Sue,Sales,39), Record(Eric,Engineering,38), Record(Sue,Management,38), Record(Bob,Sales,38), Record(Tina,Engineering,37), Record(Dan,Management,37), Record(Eric,Sales,37), Record(Dan,Engineering,36), Record(Sue,Management,36), Record(Bob,Sales,36), Record(Tina,Engineering,35), Record(Bob,Management,35), Record(Eric,Sales,35), Record(Dan,Engineering,34), Record(Sue,Management,34), Record(Tina,Sales,34), Record(Sue,Engineering,33), Record(Bob,Management,33), Record(Eric,Sales,33), Record(Dan,Engineering,32), Record(Eric,Management,32), Record(Tina,Sales,32), Record(Sue,Engineering,31), Record(Bob,Management,31), Record(Dan,Sales,31), Record(Bob,Engineering,30), Record(Eric,Management,30), Record(Tina,Sales,30)]

View File

@ -21,9 +21,9 @@ try:
try:
print("This is the inner level")
raise "This is the exception"
except as exception:
except:
print("This is the inner handler.")
raise exception
except as exception:
except:
print("This is the outer handler.")
print(exception)

View File

@ -7,7 +7,7 @@ for k,v in [(1,2),(3,4),(5,6)]:
try:
for k,v,z in [(1,2,7),(3,4,8),(5,6)]:
print(k,v,z)
except as exception:
except:
print(exception.__class__.__name__)
# 1 2 7
# 3 4 8
@ -16,7 +16,7 @@ except as exception:
try:
for k,v in [1,2,3]:
print("type error")
except as exception:
except:
print(exception.__class__.__name__)
# TypeError

Some files were not shown because too many files have changed in this diff Show More