Compare commits

...

188 Commits
v1.3 ... master

Author SHA1 Message Date
K. Lange
72b59b7972 Use stable loop power calculation 2024-03-19 10:02:14 +09:00
K. Lange
179b4e456a Fix passing keyword args to sorted() 2024-03-13 16:34:07 +09:00
K. Lange
bd2e22ddcc time.h include missing after callgrind removal 2024-03-12 07:38:51 +09:00
K. Lange
9f370f0bc6 Cleanups for callgrind tool 2024-03-07 22:16:00 +09:00
K. Lange
2ed41a0fb0 Immortalize '__main__' 2024-03-07 17:15:56 +09:00
K. Lange
5345006580 Add help text and -q options 2024-03-07 07:23:21 +09:00
K. Lange
3e6632807a New callgrind and watchdog tools 2024-03-06 20:16:48 +09:00
K. Lange
0eaa455fbe Remove callgrind generation from VM 2024-03-06 16:38:23 +09:00
K. Lange
6b134d11ff Ignore leading and trailing whitespace when parsing floats 2024-03-06 09:50:43 +09:00
K. Lange
c865e0dc78 Fix oops in str.__repr__, how did tests not catch that 2024-03-06 09:47:07 +09:00
K. Lange
66d81336ad Accept NO_COLOR to disable graying repl response values
Closes #44
2024-03-05 22:08:56 +09:00
K. Lange
ef2b18f1bf Allow themes to be disabled in rline
This still outputs ANSI color escapes, they're just always for color 9,
which is the default color for the foreground or background. rline will
always output escapes, as it's fundamentally part of how it works. If
you don't want ANSI escapes, disable rline.
2024-03-05 22:07:37 +09:00
K. Lange
7acf2cd528 Clean up str.__repr__ for small generated code 2024-03-05 18:40:36 +09:00
K. Lange
2b5df70d5a Fix up linger direct use of hasKw in long_to_bytes 2024-03-05 18:40:21 +09:00
K. Lange
dcd1fafc85 Add tool to generate huge source with overlong jumps 2024-03-05 14:45:42 +09:00
K. Lange
84203501a5 Add simple reverse sort test 2024-03-05 14:43:57 +09:00
K. Lange
34f8515d44 Add sort stability test 2024-03-05 14:39:23 +09:00
K. Lange
d9398f1eff Use string builder for repl results 2024-03-05 14:38:33 +09:00
K. Lange
9d5c9200e8 Simplify some container __repr__ implementations with %R 2024-03-05 14:38:12 +09:00
K. Lange
3e8bb098ff Raise exception if __repr__ returns non-str in pushStringBuilderFormat 2024-03-05 14:21:49 +09:00
K. Lange
6c41c32949 Implement naive powersort 2024-03-05 12:44:01 +09:00
K. Lange
62822051a9 Account for overlongjump tables in size of codeobject 2024-03-05 08:36:35 +09:00
K. Lange
4bd5988e31 Rearrange class compilation for cleaner line number mappings 2024-03-04 21:40:43 +09:00
K. Lange
5949a4998e Add PUSH_BUILD_CLASS opcode 2024-03-04 12:55:15 +09:00
K. Lange
dae53fadc4 Remove extraneous jump from tail of if without else 2024-03-04 09:58:16 +09:00
K. Lange
b1d3b7e697 Handle jump targets of over-long jumps 2024-03-04 09:51:54 +09:00
K. Lange
0bd12bdf0a Support overly-long jumps with new instruction 2024-03-03 22:18:15 +09:00
K. Lange
272d503055 Use scratch space while swapping instead of push/pop 2024-03-03 22:17:21 +09:00
K. Lange
f33cc7cac2 Has this always been wrong? 2024-03-03 22:16:03 +09:00
K. Lange
864cda1bed Cache jump targets in a hash/set 2024-03-03 22:10:07 +09:00
K. Lange
1928fa6b0c Compute line numbers through binary search, not linear scan 2024-03-03 12:11:42 +09:00
K. Lange
e801ca642e Implement list.sort with a 3-way quicksort
This is a temporary measure until a better (stable) sort is implemented,
like Timsort or powersort.
2024-03-02 21:31:49 +09:00
K. Lange
edbf322a6f Clean up sorted(), reversed(); pass kwargs to list.sort for sorted() 2024-03-02 21:30:09 +09:00
K. Lange
ea55152aac Fix two instances of OBJECT_VAL called on non-object 2024-03-02 12:37:33 +09:00
K. Lange
158f660695 Fix a few uses of legacy hasKw checks 2024-03-02 12:30:55 +09:00
K. Lange
294bd0376b Move some special method names to the special method name table 2024-03-02 12:20:58 +09:00
K. Lange
0918776d00 Don't use FLUSH when switching modes in rline 2024-03-01 20:36:37 +09:00
K. Lange
47500c833f Add rudimentary locale module 2024-03-01 10:12:54 +09:00
K. Lange
837e389b4c Bump alpha number 2024-03-01 07:48:10 +09:00
K. Lange
1fadea3027 Implement float.as_integer_ratio 2024-02-29 13:19:08 +09:00
K. Lange
b9332b2578 Implement long.__pow__ for negative exponents 2024-02-29 13:00:19 +09:00
K. Lange
f6c1bfac59 Add some test cases for printing and parsing floats 2024-02-29 10:42:35 +09:00
K. Lange
ed34101ba3 Finish up overflow handling and expand comments 2024-02-29 10:35:12 +09:00
K. Lange
21f0828424 Fix bug in krk_long_medium for negative widths 2024-02-29 10:08:03 +09:00
K. Lange
191515bbc3 Support exponential notation in lexer 2024-02-29 00:29:59 +09:00
K. Lange
34a6e30769 Use new float parser instead of strtod 2024-02-29 00:29:22 +09:00
K. Lange
ce6ddec02d Add simple float parser 2024-02-29 00:26:44 +09:00
K. Lange
cfe34614da Hopefully more correct rounding in long.__truediv__? 2024-02-28 20:56:26 +09:00
K. Lange
55debe7570 Fast long shifts 2024-02-28 19:13:12 +09:00
K. Lange
a36f6e00eb Remove unused 'exact' parameter. 2024-02-28 18:01:57 +09:00
K. Lange
1cdd9dfb1b Fix repr display of trailing zero 2024-02-28 17:58:27 +09:00
K. Lange
7ed0cd6823 Improve final construction of decimal strings 2024-02-28 17:39:47 +09:00
K. Lange
f80b5430f8 Support field width, some alignment for float.__format__ 2024-02-28 09:29:26 +09:00
K. Lange
4a2e736594 Use 10^52, as that makes more sense. 2024-02-28 07:24:27 +09:00
K. Lange
27b2d584ab Also cache 10^31 2024-02-27 19:42:43 +09:00
K. Lange
4e97099bd6 Implement float → string conversion 2024-02-27 19:37:23 +09:00
K. Lange
9ad85010bf Fix leak of tmp values in long.__truediv__ 2024-02-27 19:31:13 +09:00
K. Lange
53c08adec9 Similarly, krk_tableAdjustCapacity can use identity 2024-02-27 19:26:51 +09:00
K. Lange
1ebff2c5e5 Only check identity when populating string table 2024-02-27 19:19:11 +09:00
K. Lange
f75adeb2ca Implement long.__truediv__ through actual long division 2024-02-27 07:48:15 +09:00
K. Lange
1c75adaa51 rline should only set LC_CTYPE, and only if needed 2024-02-27 07:46:56 +09:00
K. Lange
0c8cb94b6a Quick hack for rline to not have locales break float parsing 2024-02-25 22:23:56 +09:00
K. Lange
f1d7bdaa5a Accept floats in things that use krk_long_to_int 2024-02-24 21:31:39 +09:00
K. Lange
32bd212a49 Need sys/types.h for ssize_t 2024-02-15 18:49:28 +09:00
K. Lange
2c0ab9a3e9 Fix another potential case of writing to the wrong stack 2024-02-15 17:54:50 +09:00
K. Lange
d920ff7f54 Fix leaked KrkLong in rshift_z 2024-02-15 17:49:38 +09:00
K. Lange
c179b7f4b4 Fix potential references to bad stacks due to ordering of array indexing 2024-02-15 17:48:00 +09:00
K. Lange
e9702ad37e Account for increased table sizes in getsizeof 2024-02-15 17:36:05 +09:00
K. Lange
539f217714 Only scan used entries when iterating over dicts 2024-02-15 17:22:41 +09:00
K. Lange
8acf7a9113 Make tables (dicts, methods/fields) ordered 2024-02-15 17:22:11 +09:00
K. Lange
93b5fce168 dict should do power-of-two calculation when preallocating space 2024-02-15 12:01:12 +09:00
K. Lange
2fd88b8219 krk_findEntry should not be exposed 2024-02-15 12:00:31 +09:00
K. Lange
fbf1b09514 Fix missing spaces in tools/compile 2024-02-12 12:05:26 +09:00
K. Lange
22e550ee67 Fixup bounds for negative values 2024-01-15 19:36:37 +09:00
K. Lange
049c58c40c Build strings from longs before formatting them 2024-01-15 19:27:08 +09:00
K. Lange
99dfc12a67 _ format specifier should be 3 digits for decimal, 4 for others 2024-01-15 19:25:51 +09:00
K. Lange
6e8aa9bee6 Don't pass around w as a KrkLong
We only shifting up to size_t bits anyway; expose the internal
size_t-based shifting, use that in these functions, and stop
allocating additional KrkLongs for the `w` values.

Since we only do this a few times and the values were very small,
this has minimal impact but does simplify the code a bit.
2024-01-13 16:57:07 +09:00
K. Lange
9590df3ef0 Faster binary-to-decimal conversions 2024-01-11 22:56:46 +09:00
K. Lange
b162ed889b Add support for building without nan-boxing 2024-01-11 13:36:27 +09:00
K. Lange
df4435efdc Ensure bytes are zero'd when building bytearrays 2024-01-10 21:56:23 +09:00
K. Lange
0b516fd7e2 Fix long.__rshift__ in particular to be linear
on the number of bits in the number to shift, not the amount
to shif it by
2024-01-10 13:48:08 +09:00
K. Lange
4008133a0b Fix bad value boxings 2024-01-08 17:09:24 +09:00
K. Lange
bc3024881f Fixes that should enable MSVC to build the core interpreter 2024-01-08 14:12:24 +09:00
K. Lange
c530cf20fd file names passed to krk_interpret, krk_compile, krk_runfile can be const 2024-01-08 10:53:38 +09:00
K. Lange
0a9a3c7129 Step one of trying to clean up the macro namespace 2024-01-08 09:29:52 +09:00
K. Lange
a5f5c30157 NONE_VAL and NOTIMPL_VAL don't actually take an argument 2024-01-08 09:09:29 +09:00
K. Lange
29b2f91762 Don't include sys/time.h, unused 2024-01-08 08:34:05 +09:00
K. Lange
6211f81535 Avoid passing -g to can-floor-without-libm as clang doesn't like -g with -o /dev/null 2024-01-07 21:27:54 +09:00
K. Lange
eb0d40a2ad shut clang up 2024-01-07 21:17:18 +09:00
K. Lange
e4136437c6 Add a test for expression underlining data 2024-01-07 17:51:50 +09:00
K. Lange
0c552807ff Simplify repl acquisition of build version 2024-01-07 17:40:19 +09:00
K. Lange
5bf7cf89c3 Optimize type.__call__ when __new__ is a native function 2024-01-07 15:16:53 +09:00
K. Lange
2f72a8004a Handle common case for int.__new__ better 2024-01-07 15:16:26 +09:00
K. Lange
484f0f68a1 Use krk_int_from_float for float.__int__, shortcircuit small enough values 2024-01-07 10:10:51 +09:00
K. Lange
114b66dd5c Set __hash__ to None when clearing it, to match CPython 2024-01-07 10:05:16 +09:00
K. Lange
efca612a20 Support Ellipsis in tools/compile.c 2024-01-03 14:34:17 +09:00
K. Lange
ae6ec7f233 Implement Ellipsis (...) 2024-01-01 19:36:55 +09:00
K. Lange
7f397b2c2c object.__str__ should call repr; remove extraneous __str__/__repr__ aliases 2024-01-01 19:31:54 +09:00
K. Lange
98bd980c2a Try to reduce size of debug functions by building them with -Os 2023-12-31 18:52:18 +09:00
K. Lange
a7c2f52814 Should be able to compile with just KRK_DISABLE_DEBUG without issues 2023-12-31 18:51:27 +09:00
K. Lange
a386ab7df0 Remove the long-deprecated KRK_FUNC, KRK_METHOD macros 2023-12-31 16:25:52 +09:00
K. Lange
886da1a134 Remove krk_printValue, move krk_printValueSafe to debug.c 2023-12-31 16:25:00 +09:00
K. Lange
07898d31b9 Expose expression span functionality in dis module 2023-12-31 09:46:20 +09:00
K. Lange
f3191a6067 Underline expressions in exception tracebacks.
Implements Python's PEP 657 by adding debug information
to map opcodes to their source expressions.
2023-12-31 09:46:20 +09:00
K. Lange
0c52d44d3e names array is not NULL-terminated; use 'oarg' which should be count of names at this point 2023-12-30 11:45:23 +09:00
K. Lange
c7caf52f3e Use parseArgs in dis module 2023-12-28 22:29:30 +09:00
K. Lange
643313baa0 Fix dropped references to keyword arguments in parseArgs 2023-12-28 22:04:48 +09:00
K. Lange
ebe1815075 Don't bother getting the alternate function name if we aren't raising an exception 2023-12-28 19:25:56 +09:00
K. Lange
e9b0269c91 Avoid creating strings for argument names unless necessary 2023-12-28 19:11:22 +09:00
K. Lange
d1bac84663 Cleanup headers 2023-12-28 10:20:42 +09:00
K. Lange
7023e2e1fe We've made so many incompatible changes this should be 1.5 now 2023-12-24 09:12:29 +09:00
K. Lange
4ac444be47 Generate more docs 2023-12-24 09:09:38 +09:00
K. Lange
9633ee3f72 New suite of time functions 2023-12-24 09:09:24 +09:00
K. Lange
3a74ef5e21 Add 'quiet' option, get_recursion_depth 2023-12-24 09:09:07 +09:00
K. Lange
416ed28206 Make maximumCallDepth thread-local, expose changing it when feasible 2023-12-24 09:05:52 +09:00
K. Lange
80754593ad Add pairing heap module 2023-12-22 08:26:57 +09:00
K. Lange
2685f49d24 Remove modules from import table if they raised exceptions on import 2023-12-21 10:50:08 +09:00
K. Lange
fe430bbb19 Provide a simpler interface for setting up modules that sets __name__ 2023-12-21 10:28:44 +09:00
K. Lange
6ea43c35e0 Include argument name in parseArgs type errors 2023-12-15 17:24:19 +09:00
K. Lange
031ca32ab0 extract fileio to a C module 2023-12-14 20:51:59 +09:00
K. Lange
c4d8e8de6b Accept file, flush in print 2023-12-14 20:45:10 +09:00
K. Lange
02c6f58f3c Separate 'gc' into shared module 2023-12-14 13:47:23 +09:00
K. Lange
874882d926 docs: stop calling everything the base class of all objects just because it doesn't have its own __doc__ 2023-12-14 12:30:55 +09:00
K. Lange
0a71a954c2 Make it easier to bundle C modules 2023-12-14 12:05:32 +09:00
K. Lange
5e0e3e0e22 Remove os module classes from BaseClasses
Nothing should have been referencing _Environ or stat_result.
We can move CompilerState and Cell into these available slots, as
those also should not have been used by libraries.
2023-12-14 10:09:55 +09:00
K. Lange
bd0b80827e should pass CFLAGS to can-floor-without-libm.sh as it may depend on -O option 2023-12-14 10:05:01 +09:00
K. Lange
eb105690b5 Split off 'dis' as well 2023-12-14 09:55:02 +09:00
K. Lange
8425ed5a3b os, time to C modules, as planned 2023-12-14 09:03:47 +09:00
K. Lange
91740c8573 Increase default recursion limit to 1000 to match CPython 2023-12-13 09:03:14 +09:00
K. Lange
f247bba985 Bind local name for decorated function early so it can be closed 2023-12-12 20:21:42 +09:00
K. Lange
0425becba9 Support start, end in str.startswith, str.endswith 2023-12-05 07:25:16 +09:00
K. Lange
fb6faaff1a Remove support for implicit 'exception' name in 'except' blocks 2023-11-25 12:30:52 +09:00
K. Lange
d575bf7607 Handle case of a nested exception in a 'final' 2023-11-25 12:14:05 +09:00
K. Lange
01d377555a Make tests not rely on 'exception' being an implicit name in 'except' blocks 2023-11-25 11:11:56 +09:00
K. Lange
dd9b84258b Fix up edge cases in exception handling 2023-11-24 18:32:16 +09:00
K. Lange
f41253d9ca Fresh version for next release cycle 2023-08-30 18:40:14 +09:00
K. Lange
d6486b590a v1.4.0 2023-08-28 09:56:27 +09:00
K. Lange
c24a1ca633 shared object module paths should be split on / 2023-07-20 11:47:06 +09:00
K. Lange
a8e870cc87 v1.4.0b2 2023-07-07 09:38:17 +09:00
K. Lange
6c452a91e7 bool.__format__ 2023-06-22 17:16:41 +09:00
K. Lange
cc763de706 Missing void in function prototype 2023-06-15 21:39:01 +09:00
K. Lange
eaece3db50 Experiment AF_INET6, AF_UNIX support 2023-06-15 15:09:53 +09:00
K. Lange
ed2405f46b Add a quick introspection function since we lack __dict__ 2023-06-14 13:10:57 +09:00
K. Lange
85319d7f27 Catch extraneous kwargs in __new__ with default __init__ 2023-06-13 17:36:04 +09:00
K. Lange
011a33ff43 Clear exception flag when raising new exception in 'from ... import ...' 2023-06-13 16:42:46 +09:00
K. Lange
2bc4637f5c Bump version to b1 2023-06-08 08:50:54 +09:00
K. Lange
f1003ef9d5 range.__contains__ 2023-06-08 08:50:17 +09:00
K. Lange
b88267c828 No fallback print support for floats in KRK_NO_FLOAT 2023-05-30 09:26:26 +09:00
K. Lange
7c4d622d8a No int-from-float in KRK_NO_FLOAT 2023-05-30 09:18:53 +09:00
K. Lange
f3b8858727 Ignore floats in str.__mod__ in KKR_NO_FLOAT 2023-05-30 09:10:43 +09:00
K. Lange
bff66e2b72 Replace STATIC_ONLY with KRK_STATIC_ONLY 2023-05-30 08:01:52 +09:00
K. Lange
358c6b1c78 Support building without floats 2023-05-30 07:59:28 +09:00
K. Lange
cd28d82939 implement int() with parseArgs 2023-04-20 14:26:32 +09:00
K. Lange
a5856ecd6d ceil/floor/trunc should be able to return longs 2023-03-28 12:50:12 +09:00
K. Lange
0c40e8a6fc Actually commit parseArgs test tool 2023-03-27 09:17:40 +09:00
K. Lange
3436afcf18 Convert non-floats in f, d parseArgs specifiers 2023-03-27 09:12:09 +09:00
K. Lange
e26391bc2f Automatically detect if libm is needed to support floordiv 2023-03-27 09:11:40 +09:00
K. Lange
f09f62e441 Bump alpha number 2023-03-01 07:03:18 +09:00
K. Lange
47673877f0 Assignments to *expr sequences 2023-02-28 20:09:06 +09:00
K. Lange
05209793be Expand *expr in list, set, tuple; **expr in dict 2023-02-28 17:47:45 +09:00
K. Lange
20154ba519 New opcodes to support *-expansion in collection expressions 2023-02-28 15:45:36 +09:00
K. Lange
8b99aa30f3 set.update 2023-02-28 15:44:31 +09:00
K. Lange
ed0342b955 Allow staticmethod, classmethod to be applied to native functions
This is a stop-gap before actually replacing these two functions with
descriptor objects like how they work in CPython, as that's a much
larger change that will take some time to finish.
2023-02-15 19:27:25 +09:00
K. Lange
b40b2a2f01 __get__ on super() should bind real class, not super class 2023-02-15 19:24:22 +09:00
K. Lange
7e15c40849 Support : in parseArgs format with same meaning as CPython ParseTuple 2023-02-14 22:13:31 +09:00
K. Lange
a113c5540d Add ? option to krk_parseArgs, make ! work for everything 2023-02-13 10:07:41 +09:00
K. Lange
3f5693cf43 Expose krk_isSubClass 2023-02-12 15:09:29 +09:00
K. Lange
ca1a490bbb Allow some very specific reassignments of __class__ 2023-02-12 13:46:45 +09:00
K. Lange
8711f8cae7 Support __bool__ 2023-02-12 13:38:28 +09:00
K. Lange
417a334fc0 All non-instant types should set allocSize to 0 2023-02-12 13:37:43 +09:00
K. Lange
7dc9e68367 Prevent object.__new__ from being used on classes with other C __new__ implementations 2023-02-12 07:40:05 +09:00
K. Lange
46b63fc871 Support upvalue cells as exposed objects 2023-02-12 07:40:05 +09:00
K. Lange
ffa5d7e611 krk_long_compare can not fail, so not sure why we think we can fail krk_long_add from that 2023-02-09 10:51:54 +09:00
K. Lange
0f3fe14aa3 Add a test case for that 2023-02-09 10:48:37 +09:00
K. Lange
7ae6968b5c Fix bug when adding long '-n' and 'n' 2023-02-09 10:39:24 +09:00
K. Lange
c5c8c163af Additional documentation cleanup 2023-01-28 14:20:19 +09:00
K. Lange
361f915cce Only descriptors with __set__ methods should be __get__'d preemptively 2023-01-26 20:33:40 +09:00
K. Lange
1e044c140d Support for __init_subclass__ 2023-01-26 20:01:39 +09:00
K. Lange
5d1b73b3a2 Fixes for __get__, super() with class methods, etc. 2023-01-26 19:25:10 +09:00
K. Lange
867ce85fee Additional cleanup 2023-01-26 17:52:06 +09:00
K. Lange
69e0161ce4 Ensure metaclasses stick around 2023-01-26 12:08:11 +09:00
K. Lange
81abff3d75 __init__ should always return None 2023-01-26 12:05:53 +09:00
K. Lange
8e80e04a33 Fix up implict class/static methods 2023-01-25 23:50:35 +09:00
K. Lange
429c699c00 Metaclass determination 2023-01-25 23:23:45 +09:00
K. Lange
47d703cb1e Cleanup 2023-01-25 23:23:39 +09:00
K. Lange
a6373e66c9 functioning metaclasses 2023-01-25 22:51:23 +09:00
K. Lange
617d30d804 Very initial rebuild of class creation 2023-01-25 22:10:13 +09:00
K. Lange
f9df8b22ef initial support for __new__ 2023-01-24 18:15:13 +09:00
125 changed files with 7678 additions and 2690 deletions

View File

@ -21,6 +21,10 @@ KRKMODS = $(wildcard modules/*.krk modules/*/*.krk modules/*/*/*.krk)
all: ${TARGET} ${MODULES} ${TOOLS} ${GENMODS}
ifneq ($(shell tools/can-floor-without-libm.sh "$(CC) $(filter-out -g,$(CFLAGS))"),yes)
LDLIBS += -lm
endif
ifeq (,$(findstring mingw,$(CC)))
CFLAGS += -pthread
LDLIBS += -ldl -lpthread
@ -72,10 +76,25 @@ ifdef KRK_NO_STRESS_GC
CFLAGS += -DKRK_NO_STRESS_GC=1
endif
ifdef KRK_NO_FLOAT
CFLAGS += -DKRK_NO_FLOAT=1
endif
ifdef KRK_HEAP_TAG_BYTE
CFLAGS += -DKRK_HEAP_TAG_BYTE=${KRK_HEAP_TAG_BYTE}
endif
ifdef KRK_NO_NAN_BOXING
CFLAGS += -DKRK_NO_NAN_BOXING=1
endif
ifdef KRK_BUNDLE_LIBS
KRK_BUNDLE_LIBS_CFLAG=$(patsubst %,BUNDLED(%);,${KRK_BUNDLE_LIBS})
KRK_BUNDLE_LIBS_BOBJS=$(patsubst %,src/modules/module_%.o,${KRK_BUNDLE_LIBS})
BIN_OBJS += ${KRK_BUNDLE_LIBS_BOBJS}
CFLAGS += -DKRK_BUNDLE_LIBS="${KRK_BUNDLE_LIBS_CFLAG}"
endif
.PHONY: help
help:
@ -114,6 +133,7 @@ src/debug.o: src/opcodes.h
src/value.o: src/opcodes.h
src/vm.o: src/opcodes.h
src/exceptions.o: src/opcodes.h
modules/dis.so: src/opcodes.h
%.o: %.c ${HEADERS}

View File

@ -45,8 +45,6 @@ Halts execution and calls the debugger before every instruction.
Prints a message each time the garbage collector is run.
- `KRK_GLOBAL_ENABLE_STRESS_GC`
Causes the garbage collector to be called on every allocation (from the main thread).
- `KRK_GLOBAL_CALLGRIND`
Generate tracing data. `vm.callgrindFile` must be set to a writable stream to store the intermediate data collected by the VM.
- `KRK_GLOBAL_CLEAN_OUTPUT`
Disables automatic printing of uncaught exception tracebacks. Use `krk_dumpTraceback()` to print a traceback from the exception in the current thread to `stderr`.

View File

@ -1,65 +0,0 @@
'''
@brief Tool to process VM trace reports and generate callgrind-formatted output.
'''
import kuroko
import fileio
def processFile(sourcePath: str, pid: int , cmd: str):
'''@brief Process @p sourcePath from process @p pid with command @p cmd as a VM trace file.'''
let funcs = {}
with fileio.open(sourcePath,'r') as f:
for line in f.readlines():
let callerFile, callerFunc, callerLine, calleeFile, calleeFunc, calleeLine, nsecs = line.split(' ')
nsecs = float(nsecs)
let data = funcs.get((callerFile,callerFunc),{})
let call = data.get((callerLine,calleeFile,calleeFunc,calleeLine),(0,0))
let out = (call[0] + 1, call[1] + nsecs)
data[callerLine,calleeFile,calleeFunc,calleeLine] = out
funcs[callerFile,callerFunc] = data
let called = funcs.get((calleeFile,calleeFunc),{})
let times = called.get(None,(1,0))
called[None] = (calleeLine, times[1] + nsecs)
funcs[calleeFile,calleeFunc] = called
with fileio.open(f'callgrind.out.{pid}','w') as out:
out.write('# callgrind format\n')
out.write('creator: Kuroko\n')
out.write('positions: line\n')
out.write('events: nanoseconds\n')
out.write(f'cmd: {cmd}\n\n')
def defloat(f):
let s = int(f)
let n = str(int(f * 1000000000))
if len(n) > 9: n = n[-9:]
let o = (str(s) + '0' * (9 - len(n)) + n).lstrip('0')
return o if o else '0'
def cleanfunc(func):
for s in ['<module>','<listcomp>','<setcomp>','<dictcomp>','<lambda>']:
func = func.replace(s,'['+s[1:-1]+']')
return func.replace('@','<') + '>'
for key, value in funcs.items():
let sFile, sFunc = key
out.write(f'fl={sFile}\n')
out.write(f'fn={cleanfunc(sFunc)}\n')
if not sFunc.startswith('(root)'):
let startLine, totalNsecs = value[None]
for k, v in value.items():
if not k: continue
let sourceLine, file, func, destLine = k
let count, nsecs = v
totalNsecs -= nsecs
out.write(f'{startLine} {defloat(totalNsecs)}\n')
for k, v in value.items():
if not k: continue
let sourceLine, file, func, destLine = k
let count, totalNsecs = v
if file != sFile: out.write(f'cfi={file}\n')
out.write(f'cfn={cleanfunc(func)}\n')
out.write(f'calls={count} {destLine}\n')
out.write(f'{sourceLine} {defloat(totalNsecs)}\n')
out.write('\n')

View File

@ -1,28 +0,0 @@
'''
@brief Called when 'dis' is run as the main module (-m dis)
'''
# Get the real dis
import dis
def disrec(code, seen):
let next = [code]
while next:
let co = next[0]
next = next[1:]
dis.dis(co)
for inst,size,operand in dis.examine(co):
if isinstance(operand,codeobject) and operand not in seen and operand not in next:
next.append(operand)
if next:
print()
if __name__ == '__main__':
import kuroko
if (len(kuroko.argv) < 2):
print("Usage: kuroko -m dis FILE")
return 1
import fileio
for file in kuroko.argv[1:]:
with fileio.open(file,'r') as f:
let result = dis.build(f.read(), file)
disrec(result,set())

104
modules/pheap.krk Normal file
View File

@ -0,0 +1,104 @@
'''
@brief Pairing heap.
@author K. Lange <klange@toaruos.org>
Provides a simple min-heap with insert, pop, peek, and visit.
A Kuroko implementation is provided as a backup alongside a
faster C implementation in a shared object module.
'''
def __make_pheap():
def pheap_meld(left, right, comp):
if left is None:
return right
if right is None:
return left
if comp(left[0],right[0]):
if left[1]:
right[2] = left[1]
left[1] = right
return left
else:
if right[1]:
left[2] = right[1]
right[1] = left
return right
def pheap_merge_pairs(lst, comp):
if lst is None:
return None
else if lst[2] is None:
return lst
else:
let next = lst[2]
lst[2] = None
let rest = next[2]
next[2] = None
return pheap_meld(pheap_meld(lst,next,comp), pheap_merge_pairs(rest, comp), comp)
def pheap_delete_min(heap, comp):
let subs = heap[1]
return pheap_merge_pairs(subs, comp)
def pheap_visit_heap(heap, func):
if not heap: return
func(heap)
pheap_visit_heap(heap[1], func)
pheap_visit_heap(heap[2], func)
def pheap_visit_heap_after(heap, func):
if not heap: return
pheap_visit_heap(heap[1], func)
pheap_visit_heap(heap[2], func)
func(heap)
class PHeap:
def __init__(self, comp):
'''Create a new pairing heap governed by the given comparator function.'''
self.heap = None
self.comp = comp
self.count = 0
def insert(self, value):
'''Insert a new element into the heap.'''
self.heap = pheap_meld(self.heap, [value, None, None], self.comp)
self.count += 1
def peek(self):
'''Retrieve the root (smallest) element of the heap, or None if it is empty.'''
return self.heap[0] if self.heap else None
def pop(self):
'''Remove and return the root (smallest) element of the heap. If the heap is empty, IndexError is raised.'''
let out = self.heap
if not out:
raise IndexError('pop from empty heap')
self.heap = pheap_delete_min(self.heap, self.comp)
self.count -= 1
return out[0] if out else None
def __bool__(self):
return self.heap is not None
def __len__(self):
return self.count
def visit(self, func, after=False):
'''Call a function for each element of the heap.'''
(pheap_visit_heap_after if after else pheap_visit_heap)(self.heap, func)
# Clean up qualified name.
PHeap.__qualname__ = 'PHeap'
return PHeap
# Keep the Kuroko version available for testing.
let PHeap_krk = __make_pheap()
let PHeap = PHeap_krk
# Try to load the C implementation.
try:
import _pheap
PHeap = _pheap.PHeap

View File

@ -88,8 +88,15 @@ KRK_Method(object,__dir__) {
}
KRK_Method(object,__class__) {
if (argc > 1) return krk_runtimeError(vm.exceptions->typeError, "__class__ can not be assigned");
return OBJECT_VAL(krk_getType(self));
KrkClass * current = krk_getType(self);
if (argc > 1) {
if (!IS_CLASS(argv[1])) return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not a class", argv[1]);
if (!IS_INSTANCE(argv[0]) || current->allocSize != sizeof(KrkInstance)) return krk_runtimeError(vm.exceptions->typeError, "'%T' object does not have modifiable type", argv[0]); /* TODO class? */
if (AS_CLASS(argv[1])->allocSize != sizeof(KrkInstance)) return krk_runtimeError(vm.exceptions->typeError, "'%S' type is not assignable", AS_CLASS(argv[1])->name);
AS_INSTANCE(argv[0])->_class = AS_CLASS(argv[1]);
current = AS_CLASS(argv[1]);
}
return OBJECT_VAL(current);
}
KRK_Method(object,__hash__) {
@ -100,7 +107,7 @@ KRK_Method(object,__hash__) {
}
KrkObj * obj = AS_OBJECT(self);
if (!(obj->flags & KRK_OBJ_FLAGS_VALID_HASH)) {
obj->hash = INTEGER_VAL((int)((intptr_t)self >> 3));
obj->hash = (uint32_t)((intptr_t)(obj) >> 3);
obj->flags |= KRK_OBJ_FLAGS_VALID_HASH;
}
return INTEGER_VAL(obj->hash);
@ -108,7 +115,7 @@ KRK_Method(object,__hash__) {
KRK_Method(object,__eq__) {
METHOD_TAKES_EXACTLY(1);
if (argv[0] == argv[1]) return BOOLEAN_VAL(1);
if (krk_valuesSame(argv[0],argv[1])) return BOOLEAN_VAL(1);
return NOTIMPL_VAL();
}
@ -177,6 +184,42 @@ KRK_Method(object,__setattr__) {
return krk_instanceSetAttribute_wrapper(argv[0], AS_STRING(argv[1]), argv[2]);
}
KRK_StaticMethod(object,__new__) {
KrkClass * _class = NULL;
/* We don't actually care, but we want to accept them anyway */
int _argc = 0;
const KrkValue * _args = NULL;
if (!krk_parseArgs("O!*~", (const char*[]){"cls"}, vm.baseClasses->typeClass, &_class, &_argc, &_args)) {
return NONE_VAL();
}
KrkClass * _cls = _class;
while (_cls) {
if (_cls->_new && IS_NATIVE(OBJECT_VAL(_cls->_new)) && _cls->_new != KRK_BASE_CLASS(object)->_new) {
return krk_runtimeError(vm.exceptions->typeError, "object.__new__(%S) is not safe, use %S.__new__()", _class->name, _cls->name);
}
_cls = _cls->base;
}
if (_class->_init == vm.baseClasses->objectClass->_init && (_argc || (hasKw && AS_DICT(argv[argc])->count))) {
return krk_runtimeError(vm.exceptions->typeError, "%S() takes no arguments", _class->name);
}
return OBJECT_VAL(krk_newInstance(_class));
}
KRK_Method(object,__init__) {
return NONE_VAL();
}
KRK_StaticMethod(object,__init_subclass__) {
if (!krk_parseArgs(".", (const char*[]){NULL}, NULL)) return NONE_VAL();
return NONE_VAL();
}
/**
* object.__str__() / object.__repr__()
*
@ -190,7 +233,7 @@ KRK_Method(object,__setattr__) {
* all types should have a string representation available through
* those methods.
*/
KRK_Method(object,__str__) {
KRK_Method(object,__repr__) {
KrkClass * type = krk_getType(self);
KrkValue module = NONE_VAL();
@ -219,6 +262,13 @@ _error:
return NONE_VAL();
}
KRK_Method(object,__str__) {
KrkClass * type = krk_getType(self);
if (unlikely(!type->_reprer)) return krk_runtimeError(vm.exceptions->typeError, "object is not representable");
krk_push(self);
return krk_callDirect(type->_reprer, 1);
}
KRK_Method(object,__format__) {
METHOD_TAKES_EXACTLY(1);
if (!IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]);
@ -266,7 +316,7 @@ KRK_Function(dir) {
/* Put all the keys from the globals table in it */
KrkTable * globals = krk_currentThread.frames[krk_currentThread.frameCount-1].globals;
for (size_t i = 0; i < globals->capacity; ++i) {
for (size_t i = 0; i < globals->used; ++i) {
KrkTableEntry * entry = &globals->entries[i];
if (IS_KWARGS(entry->key)) continue;
krk_writeValueArray(AS_LIST(myList), entry->key);
@ -313,19 +363,19 @@ KRK_Function(chr) {
KRK_Function(hex) {
FUNCTION_TAKES_EXACTLY(1);
trySlowMethod(OBJECT_VAL(S("__hex__")));
trySlowMethod(vm.specialMethodNames[METHOD_HEX]);
return TYPE_ERROR(int,argv[0]);
}
KRK_Function(oct) {
FUNCTION_TAKES_EXACTLY(1);
trySlowMethod(OBJECT_VAL(S("__oct__")));
trySlowMethod(vm.specialMethodNames[METHOD_OCT]);
return TYPE_ERROR(int,argv[0]);
}
KRK_Function(bin) {
FUNCTION_TAKES_EXACTLY(1);
trySlowMethod(OBJECT_VAL(S("__bin__")));
trySlowMethod(vm.specialMethodNames[METHOD_BIN]);
return TYPE_ERROR(int,argv[0]);
}
@ -340,7 +390,7 @@ int krk_unpackIterable(KrkValue iterable, void * context, int callback(void *, c
} else if (IS_list(iterable)) {
if (callback(context, AS_LIST(iterable)->values, AS_LIST(iterable)->count)) return 1;
} else if (IS_dict(iterable)) {
for (size_t i = 0; i < AS_DICT(iterable)->capacity; ++i) {
for (size_t i = 0; i < AS_DICT(iterable)->used; ++i) {
if (!IS_KWARGS(AS_DICT(iterable)->entries[i].key)) {
if (callback(context, &AS_DICT(iterable)->entries[i].key, 1)) return 1;
}
@ -471,7 +521,7 @@ KRK_Method(map,__init__) {
iters->values.values[iters->values.count++] = asIter;
}
return argv[0];
return NONE_VAL();
}
KRK_Method(map,__iter__) {
@ -535,7 +585,7 @@ KRK_Method(zip,__init__) {
iters->values.values[iters->values.count++] = asIter;
}
return argv[0];
return NONE_VAL();
}
KRK_Method(zip,__iter__) {
@ -582,7 +632,8 @@ KRK_Method(filter,__init__) {
KrkValue asIter = krk_callDirect(type->_iter, 1);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
krk_attachNamedValue(&self->fields, "_iterator", asIter);
return argv[0];
return NONE_VAL();
}
KRK_Method(filter,__iter__) {
@ -633,23 +684,23 @@ KRK_Method(filter,__call__) {
#define IS_enumerate(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(enumerate)))
#define AS_enumerate(o) (AS_INSTANCE(o))
KRK_Method(enumerate,__init__) {
METHOD_TAKES_EXACTLY(1);
KrkValue iterator;
KrkValue start = INTEGER_VAL(0);
if (hasKw) krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("start")), &start);
if (!krk_parseArgs(".V|V", (const char*[]){"iterable","start"}, &iterator, &start)) return NONE_VAL();
krk_attachNamedValue(&self->fields, "_counter", start);
/* Attach iterator */
KrkClass * type = krk_getType(argv[1]);
KrkClass * type = krk_getType(iterator);
if (!type->_iter) {
return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", argv[1]);
return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", iterator);
}
krk_push(argv[1]);
krk_push(iterator);
KrkValue asIter = krk_callDirect(type->_iter, 1);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
krk_attachNamedValue(&self->fields, "_iterator", asIter);
return argv[0];
return NONE_VAL();
}
KRK_Method(enumerate,__iter__) {
@ -706,13 +757,11 @@ static int _sum_callback(void * context, const KrkValue * values, size_t count)
}
KRK_Function(sum) {
FUNCTION_TAKES_AT_LEAST(1);
KrkValue iterable;
KrkValue base = INTEGER_VAL(0);
if (hasKw) {
krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("start")), &base);
}
if (!krk_parseArgs("V|$V", (const char*[]){"iterable","start"}, &iterable, &base)) return NONE_VAL();
struct SimpleContext context = { base };
if (krk_unpackIterable(argv[0], &context, _sum_callback)) return NONE_VAL();
if (krk_unpackIterable(iterable, &context, _sum_callback)) return NONE_VAL();
return context.base;
}
@ -767,42 +816,81 @@ KRK_Function(max) {
}
KRK_Function(print) {
KrkValue sepVal;
KrkValue endVal;
char * sep = " "; size_t sepLen = 1;
char * end = "\n"; size_t endLen = 1;
if (hasKw) {
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("sep")), &sepVal)) {
if (!IS_STRING(sepVal)) return krk_runtimeError(vm.exceptions->typeError, "'%s' should be a string, not '%T'", "sep", sepVal);
sep = AS_CSTRING(sepVal);
sepLen = AS_STRING(sepVal)->length;
}
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("end")), &endVal)) {
if (!IS_STRING(endVal)) return krk_runtimeError(vm.exceptions->typeError, "'%s' should be a string, not '%T'", "end", endVal);
end = AS_CSTRING(endVal);
endLen = AS_STRING(endVal)->length;
}
char * sep = NULL;
char * end = NULL;
size_t sepLen = 0;
size_t endLen = 0;
int remArgc;
const KrkValue * remArgv;
KrkValue file = NONE_VAL();
int flush = 0;
if (!krk_parseArgs("*z#z#Vp", (const char*[]){"sep","end","file","flush"},
&remArgc, &remArgv,
&sep, &sepLen, &end, &endLen,
&file, &flush)) {
return NONE_VAL();
}
if (!argc) {
for (size_t j = 0; j < endLen; ++j) {
fputc(end[j], stdout);
/* Set default separator and end if not provided or set to None. */
if (!sep) { sep = " "; sepLen = 1; }
if (!end) { end = "\n"; endLen = 1; }
for (int i = 0; i < remArgc; ++i) {
/* If printing through a file object, get its @c write method */
if (!IS_NONE(file)) {
krk_push(krk_valueGetAttribute(file, "write"));
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
}
}
for (int i = 0; i < argc; ++i) {
KrkValue printable = argv[i];
if (IS_STRING(printable)) { /* krk_printValue runs repr */
/* Make sure we handle nil bits correctly. */
for (size_t j = 0; j < AS_STRING(printable)->length; ++j) {
fputc(AS_CSTRING(printable)[j], stdout);
/* Convert the argument to a printable form, first by trying __str__, then __repr__ */
KrkValue printable = remArgv[i];
krk_push(printable);
if (!IS_STRING(printable)) {
KrkClass * type = krk_getType(printable);
if (type->_tostr) {
krk_push((printable = krk_callDirect(type->_tostr, 1)));
} else if (type->_reprer) {
krk_push((printable = krk_callDirect(type->_reprer, 1)));
}
if (!IS_STRING(printable)) return krk_runtimeError(vm.exceptions->typeError, "__str__ returned non-string (type %T)", printable);
}
if (!IS_NONE(file)) {
/* Call @c write */
krk_callStack(1);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
/* Print separator */
if (i + 1 < remArgc) {
krk_push(krk_valueGetAttribute(file, "write"));
krk_push(OBJECT_VAL(krk_copyString(sep,sepLen)));
krk_callStack(1);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
}
} else {
krk_printValue(stdout, printable);
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return NONE_VAL();
fwrite(AS_CSTRING(printable), AS_STRING(printable)->length, 1, stdout);
krk_pop();
if (i + 1 < remArgc) fwrite(sep, sepLen, 1, stdout);
}
char * thingToPrint = (i == argc - 1) ? end : sep;
for (size_t j = 0; j < ((i == argc - 1) ? endLen : sepLen); ++j) {
fputc(thingToPrint[j], stdout);
}
if (!IS_NONE(file)) {
/* Print end */
krk_push(krk_valueGetAttribute(file, "write"));
krk_push(OBJECT_VAL(krk_copyString(end,endLen)));
krk_callStack(1);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
/* Maybe flush */
if (flush) {
krk_push(krk_valueGetAttribute(file, "flush"));
krk_callStack(0);
}
}else {
fwrite(end, endLen, 1, stdout);
if (flush) fflush(stdout);
}
return NONE_VAL();
@ -905,22 +993,14 @@ KRK_Function(isinstance) {
}
}
static int _isSubClass(KrkClass * cls, KrkClass * base) {
while (cls) {
if (cls == base) return 1;
cls = cls->base;
}
return 0;
}
KRK_Function(issubclass) {
FUNCTION_TAKES_EXACTLY(2);
CHECK_ARG(0,class,KrkClass*,cls);
if (IS_CLASS(argv[1])) {
return BOOLEAN_VAL(_isSubClass(cls, AS_CLASS(argv[1])));
return BOOLEAN_VAL(krk_isSubClass(cls, AS_CLASS(argv[1])));
} else if (IS_TUPLE(argv[1])) {
for (size_t i = 0; i < AS_TUPLE(argv[1])->values.count; ++i) {
if (IS_CLASS(AS_TUPLE(argv[1])->values.values[i]) && _isSubClass(cls, AS_CLASS(AS_TUPLE(argv[1])->values.values[i]))) {
if (IS_CLASS(AS_TUPLE(argv[1])->values.values[i]) && krk_isSubClass(cls, AS_CLASS(AS_TUPLE(argv[1])->values.values[i]))) {
return BOOLEAN_VAL(1);
}
}
@ -1055,7 +1135,7 @@ KRK_Method(property,__init__) {
((struct Property*)self)->fset = IS_OBJECT(argv[2]) ? AS_OBJECT(argv[2]) : NULL;
}
return argv[0];
return NONE_VAL();
}
KRK_Method(property,setter) {
@ -1065,7 +1145,9 @@ KRK_Method(property,setter) {
}
KRK_Method(property,__get__) {
METHOD_TAKES_EXACTLY(1); /* the owner */
METHOD_TAKES_AT_LEAST(1); /* the owner */
if (IS_NONE(argv[1])) return argv[0];
struct Property * asProp = (struct Property *)self;
@ -1179,11 +1261,13 @@ KRK_Function(abs) {
if (IS_INTEGER(argv[0])) {
krk_integer_type i = AS_INTEGER(argv[0]);
return INTEGER_VAL(i >= 0 ? i : -i);
#ifndef KRK_NO_FLOAT
} else if (IS_FLOATING(argv[0])) {
double i = AS_FLOATING(argv[0]);
return FLOATING_VAL(i >= 0 ? i : -i);
#endif
} else {
trySlowMethod(OBJECT_VAL(S("__abs__")));
trySlowMethod(vm.specialMethodNames[METHOD_ABS]);
return krk_runtimeError(vm.exceptions->typeError, "bad operand type for 'abs()': '%T'", argv[0]);
}
}
@ -1210,14 +1294,148 @@ KRK_Function(format) {
}
static void module_sweep(KrkInstance * inst) {
#ifndef STATIC_ONLY
#ifndef KRK_STATIC_ONLY
struct KrkModule * module = (struct KrkModule*)inst;
if (module->libHandle) {
dlClose(module->libHandle);
krk_dlClose(module->libHandle);
}
#endif
}
KRK_Function(__build_class__) {
KrkValue func = NONE_VAL();
KrkString * name = NULL;
KrkClass * base = vm.baseClasses->objectClass;
KrkValue metaclass = OBJECT_VAL(vm.baseClasses->typeClass);
if (!krk_parseArgs("VO!|O!$V~",
(const char*[]){"func","name","base","metaclass"},
&func,
vm.baseClasses->strClass, &name,
vm.baseClasses->typeClass, &base,
&metaclass)) {
return NONE_VAL();
}
if (IS_CLASS(metaclass)) {
KrkClass * basemeta = base->_class ? base->_class : vm.baseClasses->typeClass;
if (krk_isSubClass(AS_CLASS(metaclass), basemeta)) {
/* good to go */
} else if (krk_isSubClass(basemeta, AS_CLASS(metaclass))) {
/* take the more derived one */
metaclass = OBJECT_VAL(basemeta);
} else {
return krk_runtimeError(vm.exceptions->typeError,
"metaclass conflict: %S is not a subclass of %S", AS_CLASS(metaclass)->name, basemeta->name);
}
}
/* Push function */
krk_push(func);
/* Call __prepare__ from metaclass */
krk_push(krk_valueGetAttribute_default(metaclass, "__prepare__", KWARGS_VAL(0)));
/* Bail early on exception */
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
if (IS_KWARGS(krk_peek(0))) {
krk_pop();
krk_push(krk_dict_of(0,NULL,0));
} else {
krk_push(OBJECT_VAL(name));
krk_push(OBJECT_VAL(base));
/* Do we have keywords? */
int args = 2;
if (hasKw) {
args += 3;
krk_push(KWARGS_VAL(KWARGS_DICT));
krk_push(argv[argc]);
krk_push(KWARGS_VAL(1));
}
krk_push(krk_callStack(args));
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
}
/* Run the class function on it */
krk_push(krk_callStack(1));
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
/* Now call the metaclass with the name, base, namespace, and kwds */
int args = 3;
krk_push(OBJECT_VAL(name));
krk_push(OBJECT_VAL(base));
krk_push(metaclass);
krk_swap(3);
if (hasKw) {
args += 3;
krk_push(KWARGS_VAL(KWARGS_DICT));
krk_push(argv[argc]);
krk_push(KWARGS_VAL(1));
}
krk_push(krk_callStack(args));
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
/* Now assign the upvalue for the original function if it's a closure. */
if (IS_CLOSURE(func)) {
if (AS_CLOSURE(func)->upvalueCount && AS_CLOSURE(func)->upvalues[0]->location == -1 && IS_NONE(AS_CLOSURE(func)->upvalues[0]->closed)) {
AS_CLOSURE(func)->upvalues[0]->closed = krk_peek(0);
}
}
/* We're done, return the resulting class object. */
return krk_pop();
}
#undef CURRENT_CTYPE
#define CURRENT_CTYPE KrkUpvalue *
#define IS_Cell(o) (krk_isObjType((o), KRK_OBJ_UPVALUE))
#define AS_Cell(o) ((KrkUpvalue*)AS_OBJECT(o))
KRK_StaticMethod(Cell,__new__) {
KrkClass * _class = NULL;
KrkValue contents = NONE_VAL();
if (!krk_parseArgs("O!|V:Cell", (const char*[]){"cls","contents"}, KRK_BASE_CLASS(type), &_class, &contents)) {
return NONE_VAL();
}
if (_class != KRK_BASE_CLASS(Cell)) {
return krk_runtimeError(vm.exceptions->typeError, "can not assemble new Cell from %R", OBJECT_VAL(_class));
}
KrkUpvalue * out = krk_newUpvalue(-1);
out->closed = contents;
return OBJECT_VAL(out);
}
#define UPVALUE_LOCATION(upvalue) (upvalue->location == -1 ? &upvalue->closed : &upvalue->owner->stack[upvalue->location])
KRK_Method(Cell,__repr__) {
struct StringBuilder sb = {0};
KrkValue contents = *UPVALUE_LOCATION(self);
if (!krk_pushStringBuilderFormat(&sb,"<cell at %p: %T object", (void*)self, contents)) goto _error;
if (IS_OBJECT(contents)) {
if (!krk_pushStringBuilderFormat(&sb, " at %p>", (void*)AS_OBJECT(contents))) goto _error;
} else {
krk_pushStringBuilder(&sb,'>');
}
return krk_finishStringBuilder(&sb);
_error:
krk_discardStringBuilder(&sb);
return NONE_VAL();
}
KRK_Method(Cell,cell_contents) {
if (argc > 1) {
*UPVALUE_LOCATION(self) = argv[1];
}
return *UPVALUE_LOCATION(self);
}
_noexport
void _createAndBind_builtins(void) {
vm.baseClasses->objectClass = krk_newClass(S("object"), NULL);
@ -1226,11 +1444,14 @@ void _createAndBind_builtins(void) {
KrkClass * object = vm.baseClasses->objectClass;
BIND_METHOD(object,__dir__);
BIND_METHOD(object,__str__);
BIND_METHOD(object,__repr__);
BIND_METHOD(object,__hash__);
BIND_METHOD(object,__eq__);
BIND_METHOD(object,__format__);
BIND_METHOD(object,__setattr__)->obj.flags = KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
krk_defineNative(&object->methods, "__repr__", FUNC_NAME(object,__str__));
BIND_STATICMETHOD(object,__setattr__);
BIND_STATICMETHOD(object,__new__);
BIND_METHOD(object,__init__);
BIND_CLASSMETHOD(object,__init_subclass__);
krk_finalizeClass(object);
KRK_DOC(object,
"@brief Base class for all types.\n\n"
@ -1247,7 +1468,6 @@ void _createAndBind_builtins(void) {
krk_push(OBJECT_VAL(module));
BIND_METHOD(module,__repr__);
krk_defineNative(&module->methods, "__str__", FUNC_NAME(module,__repr__));
krk_finalizeClass(module);
KRK_DOC(module, "Type of imported modules and packages.");
@ -1362,6 +1582,14 @@ void _createAndBind_builtins(void) {
BIND_METHOD(enumerate,__call__);
krk_finalizeClass(enumerate);
KrkClass * Cell = ADD_BASE_CLASS(KRK_BASE_CLASS(Cell), "Cell", object);
Cell->allocSize = 0;
Cell->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_STATICMETHOD(Cell,__new__);
BIND_METHOD(Cell,__repr__);
BIND_PROP(Cell,cell_contents);
krk_finalizeClass(Cell);
BUILTIN_FUNCTION("isinstance", FUNC_NAME(krk,isinstance),
"@brief Check if an object is an instance of a type.\n"
"@arguments inst, cls\n\n"
@ -1399,7 +1627,7 @@ void _createAndBind_builtins(void) {
"@c repr strings should convey all information needed to recreate the object, if this is possible.");
BUILTIN_FUNCTION("print", FUNC_NAME(krk,print),
"@brief Print text to the standard output.\n"
"@arguments *args,sep=' ',end='\\n'\n\n"
"@arguments *args,sep=' ',end='\\n',file=None,flush=False\n\n"
"Prints the string representation of each argument to the standard output. "
"The keyword argument @p sep specifies the string to print between values. "
"The keyword argument @p end specifies the string to print after all of the values have been printed.");
@ -1488,5 +1716,8 @@ void _createAndBind_builtins(void) {
BUILTIN_FUNCTION("format", FUNC_NAME(krk,format),
"@brief Format a value for string printing.\n"
"@arguments value[,format_spec]");
BUILTIN_FUNCTION("__build_class__", FUNC_NAME(krk,__build_class__),
"@brief Internal function to build a type object.\n"
"@arguments func, name, base=object, metaclass=type");
}

View File

@ -13,6 +13,7 @@ void krk_initChunk(KrkChunk * chunk) {
chunk->linesCapacity = 0;
chunk->lines = NULL;
chunk->filename = NULL;
krk_initValueArray(&chunk->constants);
}
@ -20,8 +21,8 @@ static void addLine(KrkChunk * chunk, size_t line) {
if (chunk->linesCount && chunk->lines[chunk->linesCount-1].line == line) return;
if (chunk->linesCapacity < chunk->linesCount + 1) {
int old = chunk->linesCapacity;
chunk->linesCapacity = GROW_CAPACITY(old);
chunk->lines = GROW_ARRAY(KrkLineMap, chunk->lines, old, chunk->linesCapacity);
chunk->linesCapacity = KRK_GROW_CAPACITY(old);
chunk->lines = KRK_GROW_ARRAY(KrkLineMap, chunk->lines, old, chunk->linesCapacity);
}
chunk->lines[chunk->linesCount] = (KrkLineMap){chunk->count, line};
chunk->linesCount++;
@ -30,8 +31,8 @@ static void addLine(KrkChunk * chunk, size_t line) {
void krk_writeChunk(KrkChunk * chunk, uint8_t byte, size_t line) {
if (chunk->capacity < chunk->count + 1) {
int old = chunk->capacity;
chunk->capacity = GROW_CAPACITY(old);
chunk->code = GROW_ARRAY(uint8_t, chunk->code, old, chunk->capacity);
chunk->capacity = KRK_GROW_CAPACITY(old);
chunk->code = KRK_GROW_ARRAY(uint8_t, chunk->code, old, chunk->capacity);
}
chunk->code[chunk->count] = byte;
@ -40,8 +41,8 @@ void krk_writeChunk(KrkChunk * chunk, uint8_t byte, size_t line) {
}
void krk_freeChunk(KrkChunk * chunk) {
FREE_ARRAY(uint8_t, chunk->code, chunk->capacity);
FREE_ARRAY(KrkLineMap, chunk->lines, chunk->linesCapacity);
KRK_FREE_ARRAY(uint8_t, chunk->code, chunk->capacity);
KRK_FREE_ARRAY(KrkLineMap, chunk->lines, chunk->linesCapacity);
krk_freeValueArray(&chunk->constants);
krk_initChunk(chunk);
}
@ -72,11 +73,29 @@ size_t krk_writeConstant(KrkChunk * chunk, KrkValue value, size_t line) {
}
size_t krk_lineNumber(KrkChunk * chunk, size_t offset) {
size_t line = 0;
for (size_t i = 0; i < chunk->linesCount; ++i) {
if (chunk->lines[i].startOffset > offset) break;
line = chunk->lines[i].line;
size_t lo = 0;
size_t hi = chunk->linesCount;
while (lo != hi) {
if (hi - lo < 10) {
size_t line = 0;
for (size_t i = lo; i < hi; ++i) {
if (chunk->lines[i].startOffset > offset) break;
line = chunk->lines[i].line;
}
return line;
}
size_t mp = lo + (hi - lo) / 2;
if (chunk->lines[mp].startOffset > offset) {
hi = mp;
} else {
lo = mp;
}
}
return line;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,109 @@
#ifndef KRK_DISABLE_DEBUG
#define NOOP (void)0
#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
#pragma GCC optimize ("Os")
#endif
#define STRING_DEBUG_TRUNCATE 50
void krk_printValueSafe(FILE * f, KrkValue printable) {
if (!IS_OBJECT(printable)) {
switch (KRK_VAL_TYPE(printable)) {
case KRK_VAL_INTEGER: fprintf(f, PRIkrk_int, AS_INTEGER(printable)); break;
case KRK_VAL_BOOLEAN: fprintf(f, "%s", AS_BOOLEAN(printable) ? "True" : "False"); break;
case KRK_VAL_NONE: fprintf(f, "None"); break;
case KRK_VAL_HANDLER:
switch (AS_HANDLER_TYPE(printable)) {
case OP_PUSH_TRY: fprintf(f, "{try->%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_PUSH_WITH: fprintf(f, "{with->%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_RAISE: fprintf(f, "{raise<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_FILTER_EXCEPT: fprintf(f, "{except<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_BEGIN_FINALLY: fprintf(f, "{finally<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_RETURN: fprintf(f, "{return<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_END_FINALLY: fprintf(f, "{end<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_EXIT_LOOP: fprintf(f, "{exit<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_RAISE_FROM: fprintf(f, "{reraise<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
}
break;
case KRK_VAL_KWARGS: {
if (AS_INTEGER(printable) == KWARGS_SINGLE) {
fprintf(f, "{unpack single}");
} else if (AS_INTEGER(printable) == KWARGS_LIST) {
fprintf(f, "{unpack list}");
} else if (AS_INTEGER(printable) == KWARGS_DICT) {
fprintf(f, "{unpack dict}");
} else if (AS_INTEGER(printable) == KWARGS_NIL) {
fprintf(f, "{unpack nil}");
} else if (AS_INTEGER(printable) == KWARGS_UNSET) {
fprintf(f, "{unset default}");
} else {
fprintf(f, "{sentinel=" PRIkrk_int "}",AS_INTEGER(printable));
}
break;
}
default:
#ifndef KRK_NO_FLOAT
if (IS_FLOATING(printable)) fprintf(f, "%.16g", AS_FLOATING(printable));
#endif
break;
}
} else if (IS_STRING(printable)) {
fprintf(f, "'");
/*
* Print at most STRING_DEBUG_TRUNCATE characters, as bytes, escaping anything not ASCII.
* See also str.__repr__ which does something similar with escape sequences, but this
* is a dumber, safer, and slightly faster approach.
*/
for (size_t c = 0; c < AS_STRING(printable)->length && c < STRING_DEBUG_TRUNCATE; ++c) {
unsigned char byte = (unsigned char)AS_CSTRING(printable)[c];
switch (byte) {
case '\\': fprintf(f, "\\\\"); break;
case '\n': fprintf(f, "\\n"); break;
case '\r': fprintf(f, "\\r"); break;
case '\'': fprintf(f, "\\'"); break;
default: {
if (byte < ' ' || byte > '~') {
fprintf(f, "\\x%02x", byte);
} else {
fprintf(f, "%c", byte);
}
break;
}
}
}
if (AS_STRING(printable)->length > STRING_DEBUG_TRUNCATE) {
fprintf(f,"...");
}
fprintf(f,"'");
} else {
switch (AS_OBJECT(printable)->type) {
case KRK_OBJ_CODEOBJECT: fprintf(f, "<codeobject %s>", AS_codeobject(printable)->name ? AS_codeobject(printable)->name->chars : "?"); break;
case KRK_OBJ_CLASS: fprintf(f, "<class %s>", AS_CLASS(printable)->name ? AS_CLASS(printable)->name->chars : "?"); break;
case KRK_OBJ_INSTANCE: fprintf(f, "<instance of %s>", AS_INSTANCE(printable)->_class->name->chars); break;
case KRK_OBJ_NATIVE: fprintf(f, "<nativefn %s>", ((KrkNative*)AS_OBJECT(printable))->name); break;
case KRK_OBJ_CLOSURE: fprintf(f, "<function %s>", AS_CLOSURE(printable)->function->name->chars); break;
case KRK_OBJ_BYTES: fprintf(f, "<bytes of len %ld>", (long)AS_BYTES(printable)->length); break;
case KRK_OBJ_TUPLE: {
fprintf(f, "(");
for (size_t i = 0; i < AS_TUPLE(printable)->values.count; ++i) {
krk_printValueSafe(f, AS_TUPLE(printable)->values.values[i]);
if (i + 1 != AS_TUPLE(printable)->values.count) {
fprintf(f, ",");
}
}
fprintf(f, ")");
} break;
case KRK_OBJ_BOUND_METHOD: fprintf(f, "<method %s>",
AS_BOUND_METHOD(printable)->method ? (
AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_CLOSURE ? ((KrkClosure*)AS_BOUND_METHOD(printable)->method)->function->name->chars :
(AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_NATIVE ? ((KrkNative*)AS_BOUND_METHOD(printable)->method)->name : "(unknown)")) : "(corrupt bound method)"); break;
default: fprintf(f, "<%s>", krk_typeName(printable)); break;
}
}
}
/**
* When tracing is enabled, we will present the elements on the stack with
* a safe printer; the format of values printed by krk_printValueSafe will
@ -90,20 +193,39 @@ static inline const char * opcodeClean(const char * opc) {
return &opc[3];
}
static void _overlong_jump(KrkCodeObject * func, size_t offset, size_t operand) {
for (size_t i = 0; i < func->overlongJumpsCount; ++i) {
if (func->overlongJumps[i].instructionOffset == offset) {
operand |= (int)func->overlongJumps[i].intendedTarget << 16;
size_t target = offset + 2 + operand;
if (func->overlongJumps[i].originalOpcode == OP_LOOP ||
func->overlongJumps[i].originalOpcode == OP_LOOP_ITER) {
target = offset + 2 - operand;
}
krk_tableSet(AS_DICT(func->jumpTargets), INTEGER_VAL(target), BOOLEAN_VAL(1));
return;
}
}
}
static int isJumpTarget(KrkCodeObject * func, size_t startPoint) {
KrkChunk * chunk = &func->chunk;
size_t offset = 0;
if (IS_NONE(func->jumpTargets)) {
func->jumpTargets = krk_dict_of(0,NULL,0);
#define SIMPLE(opc) case opc: size = 1; break;
#define CONSTANT(opc,more) case opc: { size_t constant __attribute__((unused)) = chunk->code[offset + 1]; size = 2; more; break; } \
case opc ## _LONG: { size_t constant __attribute__((unused)) = (chunk->code[offset + 1] << 16) | \
#define CONSTANT(opc,more) case opc: { size_t constant _unused = chunk->code[offset + 1]; size = 2; more; break; } \
case opc ## _LONG: { size_t constant _unused = (chunk->code[offset + 1] << 16) | \
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
#define OPERANDB(opc,more) case opc: { size = 2; more; break; }
#define OPERAND(opc,more) OPERANDB(opc,more) \
case opc ## _LONG: { size = 4; more; break; }
#define JUMP(opc,sign) case opc: { uint16_t jump = (chunk->code[offset + 1] << 8) | (chunk->code[offset + 2]); \
if ((size_t)(offset + 3 sign jump) == startPoint) return 1; \
krk_tableSet(AS_DICT(func->jumpTargets), INTEGER_VAL((size_t)(offset + 3 sign jump)), BOOLEAN_VAL(1)); \
size = 3; break; }
#define COMPLICATED(opc,more) case opc: size = 1; more; break;
#define OVERLONG_JUMP_MORE size += 2; _overlong_jump(func, offset+1, (chunk->code[offset + 1] << 8) | (chunk->code[offset + 2]))
#define CLOSURE_MORE \
KrkCodeObject * function = AS_codeobject(chunk->constants.values[constant]); \
for (size_t j = 0; j < function->upvalueCount; ++j) { \
@ -125,16 +247,23 @@ static int isJumpTarget(KrkCodeObject * func, size_t startPoint) {
}
offset += size;
}
return 0;
#undef SIMPLE
#undef OPERANDB
#undef OPERAND
#undef CONSTANT
#undef JUMP
#undef COMPLICATED
#undef OVERLONG_JUMP_MORE
#undef CLOSURE_MORE
#undef LOCAL_MORE
#undef EXPAND_ARGS_MORE
#undef FORMAT_VALUE_MORE
}
if (!IS_dict(func->jumpTargets)) return 0;
KrkValue garbage;
if (krk_tableGet(AS_DICT(func->jumpTargets), INTEGER_VAL(startPoint), &garbage)) return 1;
return 0;
}
#define OPARGS FILE * f, const char * fullName, size_t * size, size_t * offset, KrkCodeObject * func, KrkChunk * chunk
@ -174,6 +303,41 @@ static void _jump(OPARGS, int sign) {
*size = 3;
}
static void _complicated(OPARGS, void (*more)(OPARGS)) {
_print_opcode(OPARG_VALS);
if (more) more(OPARG_VALS);
else *size = 1;
}
#define SIMPLE(opc)
#define JUMP(opc,sign) case opc: fprintf(f, "(%s, to %zu)", opcodeClean(#opc), *offset + 3 sign current_jump); return;
#define OPERAND(opc,more)
#define CONSTANT(opc,more)
#define COMPLICATED(opc,more)
static void _overlong_jump_more(OPARGS) {
size_t current_jump = (chunk->code[*offset + 1] << 8) | (chunk->code[*offset + 2]);
*size = 3;
/* Now look it up */
for (size_t i = 0; i < func->overlongJumpsCount; ++i) {
if (*offset + 1 == (size_t)func->overlongJumps[i].instructionOffset) {
current_jump |= ((size_t)func->overlongJumps[i].intendedTarget << 16);
switch (func->overlongJumps[i].originalOpcode) {
#include "opcodes.h"
default: break;
}
}
}
fprintf(f,"(invalid destination)");
}
#undef SIMPLE
#undef OPERAND
#undef CONSTANT
#undef JUMP
#undef COMPLICATED
#undef NOOP
#define NOOP (NULL)
#define SIMPLE(opc) case opc: _simple(f,#opc,&size,&offset,func,chunk); break;
@ -182,6 +346,9 @@ static void _jump(OPARGS, int sign) {
#define OPERAND(opc,more) case opc: _operand(f,#opc,&size,&offset,func,chunk,0,more); break; \
case opc ## _LONG: _operand(f,#opc "_LONG",&size,&offset,func,chunk,1,more); break;
#define JUMP(opc,sign) case opc: _jump(f,#opc,&size,&offset,func,chunk,sign 1); break;
#define COMPLICATED(opc,more) case opc: _complicated(f,#opc,&size,&offset,func,chunk,more); break;
#define OVERLONG_JUMP_MORE _overlong_jump_more
#define CLOSURE_MORE _closure_more
@ -202,6 +369,8 @@ static void _closure_more(OPARGS, size_t constant) {
break;
}
}
} else if (isLocal & 4) {
fprintf(f, "classcell");
} else { fprintf(f, "upvalue<%d>", index); }
if (j + 1 != function->upvalueCount) fprintf(f, ", ");
}
@ -289,34 +458,14 @@ size_t krk_disassembleInstruction(FILE * f, KrkCodeObject * func, size_t offset)
#undef OPERAND
#undef CONSTANT
#undef JUMP
#undef COMPLICATED
#undef OVERLONG_JUMP_MORE
#undef CLOSURE_MORE
#undef LOCAL_MORE
#undef EXPAND_ARGS_MORE
#undef FORMAT_VALUE_MORE
#undef NOOP
struct BreakpointEntry {
KrkCodeObject * inFunction;
size_t offset;
int flags;
uint8_t originalOpcode;
};
#define MAX_BREAKPOINTS 32
struct DebuggerState {
int breakpointsCount;
KrkDebugCallback debuggerHook;
/* XXX This was previously thread-local; it probably should still be
* specific to an individual thread... but we don't really do
* much thread debugging, so... */
int repeatStack_top;
int repeatStack_bottom;
int thisWasForced;
struct BreakpointEntry breakpoints[MAX_BREAKPOINTS];
};
int krk_debug_addBreakpointCodeOffset(KrkCodeObject * target, size_t offset, int flags) {
int index = vm.dbgState->breakpointsCount;
if (vm.dbgState->breakpointsCount == MAX_BREAKPOINTS) {
@ -389,12 +538,6 @@ int krk_debug_enableBreakpoint(int breakIndex) {
vm.dbgState->breakpoints[breakIndex].inFunction->chunk.code[vm.dbgState->breakpoints[breakIndex].offset] = OP_BREAKPOINT;
return 0;
}
KRK_Function(enablebreakpoint) {
CHECK_ARG(0,int,krk_integer_type,breakIndex);
if (krk_debug_enableBreakpoint(breakIndex))
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
return NONE_VAL();
}
int krk_debug_disableBreakpoint(int breakIndex) {
if (breakIndex < 0 || breakIndex >= vm.dbgState->breakpointsCount || vm.dbgState->breakpoints[breakIndex].inFunction == NULL)
@ -406,12 +549,6 @@ int krk_debug_disableBreakpoint(int breakIndex) {
}
return 0;
}
KRK_Function(disablebreakpoint) {
CHECK_ARG(0,int,krk_integer_type,breakIndex);
if (krk_debug_disableBreakpoint(breakIndex))
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
return NONE_VAL();
}
int krk_debug_removeBreakpoint(int breakIndex) {
if (breakIndex < 0 || breakIndex >= vm.dbgState->breakpointsCount || vm.dbgState->breakpoints[breakIndex].inFunction == NULL)
@ -423,61 +560,6 @@ int krk_debug_removeBreakpoint(int breakIndex) {
}
return 0;
}
KRK_Function(delbreakpoint) {
CHECK_ARG(0,int,krk_integer_type,breakIndex);
if (krk_debug_removeBreakpoint(breakIndex))
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
return NONE_VAL();
}
KRK_Function(addbreakpoint) {
FUNCTION_TAKES_EXACTLY(2);
CHECK_ARG(1,int,krk_integer_type,lineNo);
int flags = KRK_BREAKPOINT_NORMAL;
if (hasKw) {
KrkValue flagsValue = NONE_VAL();
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("flags")), &flagsValue)) {
if (!IS_INTEGER(flagsValue))
return TYPE_ERROR(int,flagsValue);
flags = AS_INTEGER(flagsValue);
}
}
int result;
if (IS_STRING(argv[0])) {
result = krk_debug_addBreakpointFileLine(AS_STRING(argv[0]), lineNo, flags);
} else {
KrkCodeObject * target = NULL;
if (IS_CLOSURE(argv[0])) {
target = AS_CLOSURE(argv[0])->function;
} else if (IS_BOUND_METHOD(argv[0]) && IS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(argv[0])->method))) {
target = AS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(argv[0])->method))->function;
} else if (IS_codeobject(argv[0])) {
target = AS_codeobject(argv[0]);
} else {
return TYPE_ERROR(function or method or filename,argv[0]);
}
/* Figure out what instruction this should be on */
size_t last = 0;
for (size_t i = 0; i < target->chunk.linesCount; ++i) {
if (target->chunk.lines[i].line > (size_t)lineNo) break;
if (target->chunk.lines[i].line == (size_t)lineNo) {
last = target->chunk.lines[i].startOffset;
break;
}
last = target->chunk.lines[i].startOffset;
}
result = krk_debug_addBreakpointCodeOffset(target,last,flags);
}
if (result < 0)
return krk_runtimeError(vm.exceptions->baseException, "Could not add breakpoint.");
return INTEGER_VAL(result);
}
/*
* Begin debugger utility functions.
*
@ -614,237 +696,46 @@ int krk_debugBreakpointHandler(void) {
return krk_debuggerHook(frame);
}
/**
* dis.dis(object)
*/
KRK_Function(dis) {
FUNCTION_TAKES_EXACTLY(1);
if (IS_CLOSURE(argv[0])) {
KrkCodeObject * func = AS_CLOSURE(argv[0])->function;
krk_disassembleCodeObject(stdout, func, func->name ? func->name->chars : "<unnamed>");
} else if (IS_codeobject(argv[0])) {
krk_disassembleCodeObject(stdout, AS_codeobject(argv[0]), AS_codeobject(argv[0])->name ? AS_codeobject(argv[0])->name->chars : "<unnamed>");
} else if (IS_BOUND_METHOD(argv[0])) {
if (AS_BOUND_METHOD(argv[0])->method->type == KRK_OBJ_CLOSURE) {
KrkCodeObject * func = ((KrkClosure*)AS_BOUND_METHOD(argv[0])->method)->function;
const char * methodName = func->name ? func->name->chars : "<unnamed>";
const char * typeName = IS_CLASS(AS_BOUND_METHOD(argv[0])->receiver) ? AS_CLASS(AS_BOUND_METHOD(argv[0])->receiver)->name->chars : krk_typeName(AS_BOUND_METHOD(argv[0])->receiver);
size_t allocSize = strlen(methodName) + strlen(typeName) + 2;
char * tmp = malloc(allocSize);
snprintf(tmp, allocSize, "%s.%s", typeName, methodName);
krk_disassembleCodeObject(stdout, func, tmp);
free(tmp);
} else {
krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%T'", AS_BOUND_METHOD(argv[0])->receiver);
}
} else if (IS_CLASS(argv[0])) {
KrkValue code;
if (krk_tableGet(&AS_CLASS(argv[0])->methods, OBJECT_VAL(S("__func__")), &code) && IS_CLOSURE(code)) {
KrkCodeObject * func = AS_CLOSURE(code)->function;
krk_disassembleCodeObject(stdout, func, AS_CLASS(argv[0])->name->chars);
}
/* TODO Methods! */
} else {
krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%T'", argv[0]);
}
return NONE_VAL();
}
KRK_Function(build) {
FUNCTION_TAKES_AT_LEAST(1);
FUNCTION_TAKES_AT_MOST(2);
CHECK_ARG(0,str,KrkString*,code);
char * fileName = "<source>";
if (argc > 1) {
CHECK_ARG(1,str,KrkString*,filename);
fileName = filename->chars;
}
/* Unset module */
krk_push(OBJECT_VAL(krk_currentThread.module));
KrkInstance * module = krk_currentThread.module;
krk_currentThread.module = NULL;
KrkCodeObject * c = krk_compile(code->chars,fileName);
krk_currentThread.module = module;
krk_pop();
if (c) return OBJECT_VAL(c);
else return NONE_VAL();
}
#define NOOP (void)0
#define SIMPLE(opc) case opc: size = 1; break;
#define CONSTANT(opc,more) case opc: { constant = chunk->code[offset + 1]; size = 2; more; break; } \
case opc ## _LONG: { constant = (chunk->code[offset + 1] << 16) | \
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
#define OPERAND(opc,more) case opc: { operand = chunk->code[offset + 1]; size = 2; more; break; } \
case opc ## _LONG: { operand = (chunk->code[offset + 1] << 16) | \
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
#define JUMP(opc,sign) case opc: { jump = 0 sign ((chunk->code[offset + 1] << 8) | (chunk->code[offset + 2])); \
size = 3; break; }
#define CLOSURE_MORE \
KrkCodeObject * function = AS_codeobject(chunk->constants.values[constant]); \
size_t baseOffset = offset; \
for (size_t j = 0; j < function->upvalueCount; ++j) { \
int isLocal = chunk->code[baseOffset++ + size]; \
baseOffset++; \
if (isLocal & 2) { \
baseOffset += 2; \
} \
} \
size += baseOffset - offset;
#define EXPAND_ARGS_MORE
#define FORMAT_VALUE_MORE
#define LOCAL_MORE local = operand;
static KrkValue _examineInternal(KrkCodeObject* func) {
KrkValue output = krk_list_of(0,NULL,0);
krk_push(output);
KrkChunk * chunk = &func->chunk;
size_t offset = 0;
while (offset < chunk->count) {
uint8_t opcode = chunk->code[offset];
size_t size = 0;
ssize_t constant = -1;
ssize_t jump = 0;
ssize_t operand = -1;
ssize_t local = -1;
switch (opcode) {
#include "opcodes.h"
}
KrkTuple * newTuple = krk_newTuple(3);
krk_push(OBJECT_VAL(newTuple));
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(opcode);
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(size);
if (constant != -1) {
newTuple->values.values[newTuple->values.count++] = chunk->constants.values[constant];
} else if (jump != 0) {
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(jump);
} else if (local != -1) {
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand); /* Just in case */
for (size_t i = 0; i < func->localNameCount; ++i) {
if (func->localNames[i].id == (size_t)local && func->localNames[i].birthday <= offset && func->localNames[i].deathday >= offset) {
newTuple->values.values[newTuple->values.count-1] = OBJECT_VAL(func->localNames[i].name);
break;
}
}
} else if (operand != -1) {
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand);
} else {
newTuple->values.values[newTuple->values.count++] = NONE_VAL();
}
krk_writeValueArray(AS_LIST(output), krk_peek(0));
krk_pop();
if (size == 0) {
abort();
}
offset += size;
}
return krk_pop();
}
KRK_Function(examine) {
FUNCTION_TAKES_EXACTLY(1);
CHECK_ARG(0,codeobject,KrkCodeObject*,func);
return _examineInternal(func);
}
#undef SIMPLE
#undef OPERANDB
#undef OPERAND
#undef CONSTANT
#undef JUMP
#undef CLOSURE_MORE
#undef LOCAL_MORE
#undef EXPAND_ARGS_MORE
#undef FORMAT_VALUE_MORE
void krk_module_init_dis(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "dis", (KrkObj*)module);
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("dis"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
void krk_debug_init(void) {
vm.dbgState = calloc(1, sizeof(struct DebuggerState));
vm.dbgState->repeatStack_top = -1;
vm.dbgState->repeatStack_bottom = -1;
}
KRK_DOC(module,
"@brief Provides tools for disassembling bytecode.\n\n"
"### Code Disassembly in Kuroko\n\n"
"The @c dis module contains functions for dealing with _code objects_ which "
"represent the compiled bytecode of a Kuroko function. The bytecode compilation "
"process is entirely static and bytecode analysis can be performed without calling "
"into the VM to run dynamic code.\n\n"
"### Debugger Breakpoints\n\n"
"Kuroko interpreters can provide a debugger hook through the C API's "
"@ref krk_debug_registerCallback() function. Breakpoints can be managed both "
"from the C API and from this module's @ref addbreakpoint, @ref delbreakpoint, "
"@ref enablebreakpoint, and @ref disablebreakpoint methods."
);
void krk_debug_addExpression(KrkCodeObject * codeobject, uint8_t start, uint8_t midStart, uint8_t midEnd, uint8_t end) {
/* Traceback entries point to the last byte of an opcode, due to the way instruction fetch
* advances the instruction pointer past all of the constituent operands of an opcode; as
* such, our map is based on these last bytes and we need to look at the byte preceding
* the current count when adding new entries. */
size_t offset = codeobject->chunk.count - 1;
KRK_DOC(BIND_FUNC(module, dis),
"@brief Disassemble an object.\n"
"@arguments obj\n\n"
"Dumps a disassembly of the bytecode in the code object associated with @p obj. "
"If @p obj can not be disassembled, a @ref TypeError is raised.");
/* We can feasibly support offsets larger than UINT32_MAX on 64-bit platforms, though this
* should never really happen. Just in case, avoid messing up our table with bad values. */
if (offset > UINT32_MAX) return;
KRK_DOC(BIND_FUNC(module, build),
"@brief Compile a string to a code object.\n"
"@arguments code\n\n"
"Compiles the string @p code and returns a code object. If a syntax "
"error is encountered, it will be raised.");
if (codeobject->expressionsCapacity < codeobject->expressionsCount + 1) {
size_t old = codeobject->expressionsCapacity;
codeobject->expressionsCapacity = KRK_GROW_CAPACITY(old);
codeobject->expressions = KRK_GROW_ARRAY(KrkExpressionsMap, codeobject->expressions, old, codeobject->expressionsCapacity);
}
KRK_DOC(BIND_FUNC(module, examine),
"@brief Convert a code object to a list of instructions.\n"
"@arguments func\n\n"
"Examines the code object @p func and returns a list representation of its instructions. "
"Each instruction entry is a tuple of the opcode, total instruction size in bytes, and "
"the operand of the argument, either as an integer for jump offsets, the actual value for "
"constant operands, or the name of a local or global variable if available.");
codeobject->expressions[codeobject->expressionsCount] = (KrkExpressionsMap){offset,start,midStart,midEnd,end};
codeobject->expressionsCount++;
}
KRK_DOC(BIND_FUNC(module, addbreakpoint),
"@brief Attach a breakpoint to a code object.\n"
"@arguments func, line\n\n"
"@p func may be a filename string, or a function, method, or code object. Returns "
"the new breakpoint index, or raises @ref Exception if a breakpoint code not be added.");
KRK_DOC(BIND_FUNC(module, delbreakpoint),
"@brief Delete a breakpoint.\n"
"@arguments handle\n\n"
"Delete the breakpoint specified by @p handle, disabling it if it was enabled. "
"May raise @ref IndexError if @p handle is not a valid breakpoint handle.");
KRK_DOC(BIND_FUNC(module, enablebreakpoint),
"@brief Enable a breakpoint.\n"
"@arguments handle\n\n"
"Enable the breakpoint specified by @p handle. May raise @ref IndexError if "
"@p handle is not a valid breakpoint handle.");
KRK_DOC(BIND_FUNC(module, disablebreakpoint),
"@brief Disable a breakpoint.\n"
"@arguments handle\n\n"
"Disable the breakpoint specified by @p handle. May raise @ref IndexError if "
"@p handle is not a valid breakpoint handle.");
krk_attachNamedValue(&module->fields, "BREAKPOINT_ONCE", INTEGER_VAL(KRK_BREAKPOINT_ONCE));
krk_attachNamedValue(&module->fields, "BREAKPOINT_REPEAT", INTEGER_VAL(KRK_BREAKPOINT_REPEAT));
#define OPCODE(opc) krk_attachNamedValue(&module->fields, #opc, INTEGER_VAL(opc));
#define SIMPLE(opc) OPCODE(opc)
#define CONSTANT(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
#define OPERAND(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
#define JUMP(opc,sign) OPCODE(opc)
#include "opcodes.h"
#undef SIMPLE
#undef OPERANDB
#undef OPERAND
#undef CONSTANT
#undef JUMP
int krk_debug_expressionUnderline(const KrkCodeObject* codeobject, uint8_t* start, uint8_t* midStart, uint8_t* midEnd, uint8_t* end, size_t instruction) {
/* We could do binary search here, but as we only print these when an exception 'escapes',
* it's not really worth the optimization over a linear search per line in the traceback. */
for (size_t i = 0; i < codeobject->expressionsCount; ++i) {
if (codeobject->expressions[i].bytecodeOffset == instruction) {
*start = codeobject->expressions[i].start;
*midStart = codeobject->expressions[i].midStart;
*midEnd = codeobject->expressions[i].midEnd;
*end = codeobject->expressions[i].end;
return 1;
}
}
return 0;
}
#endif

View File

@ -45,7 +45,7 @@ KRK_Method(BaseException,__init__) {
}
krk_attachNamedValue(&self->fields, "__cause__", NONE_VAL());
krk_attachNamedValue(&self->fields, "__context__", NONE_VAL());
return argv[0];
return NONE_VAL();
}
/**
@ -273,7 +273,7 @@ static void dumpInnerException(KrkValue exception, int depth) {
lineNo,
(function->name ? function->name->chars : "(unnamed)"));
#ifndef NO_SOURCE_IN_TRACEBACK
#ifndef KRK_NO_SOURCE_IN_TRACEBACK
/* Try to open the file */
if (function->chunk.filename) {
FILE * f = fopen(function->chunk.filename->chars, "r");
@ -288,12 +288,27 @@ static void dumpInnerException(KrkValue exception, int depth) {
}
if (line == lineNo) {
fprintf(stderr," ");
while (c == ' ') c = fgetc(f);
unsigned short j = 1;
while (c == ' ' || c == '\t') {
c = fgetc(f);
j++;
}
do {
fputc(c, stderr);
c = fgetc(f);
} while (!feof(f) && c > 0 && c != '\n');
fprintf(stderr, "\n");
#ifndef KRK_DISABLE_DEBUG
uint8_t start, midStart, midEnd, end;
if (krk_debug_expressionUnderline(function, &start, &midStart, &midEnd, &end, instruction)) {
fprintf(stderr," ");
for (; j < start; ++j) fprintf(stderr," ");
for (; j < midStart; ++j) fprintf(stderr,"~");
for (; j < midEnd; ++j) fprintf(stderr, "^");
for (; j < end; ++j) fprintf(stderr,"~");
fprintf(stderr,"\n");
}
#endif
break;
}
} while (!feof(f));
@ -461,7 +476,7 @@ KrkValue krk_runtimeError(KrkClass * type, const char * fmt, ...) {
/* Allocate an exception object of the requested type. */
KrkInstance * exceptionObject = krk_newInstance(type);
krk_push(OBJECT_VAL(exceptionObject));
krk_attachNamedValue(&exceptionObject->fields, "arg", msg == KWARGS_VAL(0) ? finishStringBuilder(&sb) : msg);
krk_attachNamedValue(&exceptionObject->fields, "arg", krk_valuesSame(msg,KWARGS_VAL(0)) ? finishStringBuilder(&sb) : msg);
krk_attachNamedValue(&exceptionObject->fields, "__cause__", NONE_VAL());
krk_attachNamedValue(&exceptionObject->fields, "__context__", NONE_VAL());
krk_pop();

View File

@ -33,11 +33,10 @@
#define PROMPT_MAIN ">>> "
#define PROMPT_BLOCK " > "
#define CALLGRIND_TMP_FILE "/tmp/kuroko.callgrind.tmp"
static int enableRline = 1;
static int exitRepl = 0;
static int pasteEnabled = 0;
static int noColor = 0;
KRK_Function(exit) {
FUNCTION_TAKES_NONE();
@ -128,6 +127,16 @@ KRK_Function(input) {
return readLine(prompt, promptwidth, syntax);
}
static void printResult(FILE * file, KrkValue result) {
struct StringBuilder sb = {0};
if (!krk_pushStringBuilderFormat(&sb, noColor ? " => %R\n" : " \033[1;90m=> %R\033[0m\n", result)) {
krk_dumpTraceback();
} else {
fwrite(sb.bytes,1,sb.length,file);
}
krk_discardStringBuilder(&sb);
}
#ifndef NO_RLINE
/**
* Given an object, find a property with the same name as a scanner token.
@ -468,9 +477,7 @@ static int debuggerHook(KrkCallFrame * frame) {
krk_pop();
/* Call the compiled expression with no args. */
krk_push(krk_callStack(0));
fprintf(stderr, "\033[1;30m=> ");
krk_printValue(stderr, krk_peek(0));
fprintf(stderr, "\033[0m\n");
printResult(stderr, krk_peek(0));
krk_pop();
}
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
@ -744,16 +751,6 @@ static int compileFile(char * argv[], int flags, char * fileName) {
return func == NULL;
}
#ifdef BUNDLE_LIBS
#define BUNDLED(name) do { \
extern KrkValue krk_module_onload_ ## name (); \
KrkValue moduleOut = krk_module_onload_ ## name (); \
krk_attachNamedValue(&vm.modules, # name, moduleOut); \
krk_attachNamedObject(&AS_INSTANCE(moduleOut)->fields, "__name__", (KrkObj*)krk_copyString(#name, sizeof(#name)-1)); \
krk_attachNamedValue(&AS_INSTANCE(moduleOut)->fields, "__file__", NONE_VAL()); \
} while (0)
#endif
int main(int argc, char * argv[]) {
#ifdef _WIN32
SetConsoleOutputCP(65001);
@ -788,11 +785,6 @@ int main(int argc, char * argv[]) {
/* Disassemble instructions as they are executed. */
flags |= KRK_THREAD_ENABLE_TRACING;
break;
case 'T': {
flags |= KRK_GLOBAL_CALLGRIND;
vm.callgrindFile = fopen(CALLGRIND_TMP_FILE,"w");
break;
}
case 'i':
inspectAfter = 1;
break;
@ -838,7 +830,6 @@ int main(int argc, char * argv[]) {
" -r Disable complex line editing in the REPL.\n"
" -R depth Set maximum recursion depth.\n"
" -t Disassemble instructions as they are exceuted.\n"
" -T Write call trace file.\n"
" -C file Compile 'file', but do not execute it.\n"
" -M Print the default module import paths.\n"
" -S Enable single-step debugging.\n"
@ -885,20 +876,26 @@ _finishArgs:
/* Bind interrupt signal */
bindSignalHandlers();
#ifdef BUNDLE_LIBS
/* Add any other modules you want to include that are normally built as shared objects. */
BUNDLED(math);
BUNDLED(socket);
BUNDLED(timeit);
#ifdef KRK_BUNDLE_LIBS
/* Define KRK_BUNDLE_LIBS like "BUNDLE(os);BUNDLE(math);", etc. */
#define BUNDLED(name) do { \
extern KrkValue krk_module_onload_ ## name (KrkString*); \
KrkValue moduleOut = krk_module_onload_ ## name (NULL); \
krk_attachNamedValue(&vm.modules, # name, moduleOut); \
krk_attachNamedObject(&AS_INSTANCE(moduleOut)->fields, "__name__", (KrkObj*)krk_copyString(#name, sizeof(#name)-1)); \
krk_attachNamedValue(&AS_INSTANCE(moduleOut)->fields, "__file__", NONE_VAL()); \
} while (0)
KRK_BUNDLE_LIBS
#undef BUNDLED
#endif
KrkValue result = INTEGER_VAL(0);
char * _KUROKOPATH = getenv("KUROKOPATH");
char * env_KUROKOPATH = getenv("KUROKOPATH");
if (_KUROKOPATH) {
if (env_KUROKOPATH) {
/* Build a path by splitting */
krk_push(OBJECT_VAL(krk_copyString(_KUROKOPATH,strlen(_KUROKOPATH))));
krk_push(OBJECT_VAL(krk_copyString(env_KUROKOPATH,strlen(env_KUROKOPATH))));
krk_push(OBJECT_VAL(S(":")));
/* Split into list */
@ -922,12 +919,16 @@ _finishArgs:
krk_pop(); /* list */
}
char * env_NO_COLOR = getenv("NO_COLOR");
if (env_NO_COLOR && *env_NO_COLOR) noColor = 1;
/**
* Add general builtins that aren't part of the core VM.
* This is where we provide @c input in particular.
*/
KRK_DOC(BIND_FUNC(vm.builtins,input), "@brief Read a line of input.\n"
"@arguments [prompt], promptwidth=None, syntax=None\n\n"
"@arguments prompt='',promptwidth=0,syntax=None\n\n"
"Read a line of input from @c stdin. If the @c rline library is available, "
"it will be used to gather input. Input reading stops on end-of file or when "
"a read ends with a line feed, which will be removed from the returned string. "
@ -941,10 +942,7 @@ _finishArgs:
"provide color highlighting of the input line.");
if (moduleAsMain) {
krk_push(OBJECT_VAL(krk_copyString("__main__",8)));
int out = !krk_importModule(
AS_STRING(AS_LIST(argList)->values[0]),
AS_STRING(krk_peek(0)));
int out = !krk_importModule(AS_STRING(AS_LIST(argList)->values[0]), S("__main__"));
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
krk_dumpTraceback();
krk_resetStack();
@ -990,12 +988,11 @@ _finishArgs:
* This module won't be imported by default, but it's still in
* the modules list, so we can look for it there.
*/
KrkValue systemModule;
if (krk_tableGet(&vm.modules, OBJECT_VAL(krk_copyString("kuroko",6)), &systemModule)) {
if (vm.system) {
KrkValue version, buildenv, builddate;
krk_tableGet(&AS_INSTANCE(systemModule)->fields, OBJECT_VAL(krk_copyString("version",7)), &version);
krk_tableGet(&AS_INSTANCE(systemModule)->fields, OBJECT_VAL(krk_copyString("buildenv",8)), &buildenv);
krk_tableGet(&AS_INSTANCE(systemModule)->fields, OBJECT_VAL(krk_copyString("builddate",9)), &builddate);
krk_tableGet_fast(&vm.system->fields, S("version"), &version);
krk_tableGet_fast(&vm.system->fields, S("buildenv"), &buildenv);
krk_tableGet_fast(&vm.system->fields, S("builddate"), &builddate);
fprintf(stdout, "Kuroko %s (%s) with %s\n",
AS_CSTRING(version), AS_CSTRING(builddate), AS_CSTRING(buildenv));
@ -1006,7 +1003,7 @@ _finishArgs:
while (!exitRepl) {
size_t lineCapacity = 8;
size_t lineCount = 0;
char ** lines = ALLOCATE(char *, lineCapacity);
char ** lines = KRK_ALLOCATE(char *, lineCapacity);
size_t totalData = 0;
int valid = 1;
char * allData = NULL;
@ -1092,8 +1089,8 @@ _finishArgs:
if (lineCapacity < lineCount + 1) {
/* If we need more space, grow as needed... */
size_t old = lineCapacity;
lineCapacity = GROW_CAPACITY(old);
lines = GROW_ARRAY(char *,lines,old,lineCapacity);
lineCapacity = KRK_GROW_CAPACITY(old);
lines = KRK_GROW_ARRAY(char *,lines,old,lineCapacity);
}
int i = lineCount++;
@ -1162,26 +1159,13 @@ _finishArgs:
#endif
free(lines[i]);
}
FREE_ARRAY(char *, lines, lineCapacity);
KRK_FREE_ARRAY(char *, lines, lineCapacity);
if (valid) {
KrkValue result = krk_interpret(allData, "<stdin>");
if (!IS_NONE(result)) {
krk_attachNamedValue(&vm.builtins->fields, "_", result);
KrkClass * type = krk_getType(result);
const char * formatStr = " \033[1;90m=> %s\033[0m\n";
if (type->_reprer) {
krk_push(result);
result = krk_callDirect(type->_reprer, 1);
} else if (type->_tostr) {
krk_push(result);
result = krk_callDirect(type->_tostr, 1);
}
if (!IS_STRING(result)) {
fprintf(stdout, " \033[1;91m=> Unable to produce representation for value.\033[0m\n");
} else {
fprintf(stdout, formatStr, AS_CSTRING(result));
}
printResult(stdout, result);
}
krk_resetStack();
free(allData);
@ -1191,20 +1175,6 @@ _finishArgs:
}
}
if (vm.globalFlags & KRK_GLOBAL_CALLGRIND) {
fclose(vm.callgrindFile);
vm.globalFlags &= ~(KRK_GLOBAL_CALLGRIND);
krk_resetStack();
krk_startModule("<callgrind>");
krk_attachNamedObject(&krk_currentThread.module->fields, "filename", (KrkObj*)S(CALLGRIND_TMP_FILE));
krk_interpret(
"from callgrind import processFile\n"
"import kuroko\n"
"import os\n"
"processFile(filename, os.getpid(), ' '.join(kuroko.argv))","<callgrind>");
}
krk_freeVM();
if (IS_INTEGER(result)) return AS_INTEGER(result);

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

View File

@ -206,6 +206,11 @@ extern int krk_debug_examineBreakpoint(int breakIndex, KrkCodeObject ** funcOut,
*/
extern void krk_debug_dumpStack(FILE * f, KrkCallFrame * frame);
/**
* @brief Initialize debugger state. Call exactly once per VM.
*/
extern void krk_debug_init(void);
/**
* @def KRK_BREAKPOINT_NORMAL
*
@ -233,4 +238,55 @@ extern void krk_debug_dumpStack(FILE * f, KrkCallFrame * frame);
#define KRK_DEBUGGER_RAISE 3
#define KRK_DEBUGGER_QUIT 4
/**
* @brief Add an expression mapping to the bytecode chunk.
* @memberof KrkCodeObject
*
* Associates a span of columns representing an expression with the
* current opcode offset. Used to supply debug information displayed
* in tracebacks with tildes and carets.
*
* @param codeobject Codeobject containing the instruction.
* @param start First column, 1-indexed, of tildes, left side of expression.
* @param midStart First column, 1-indexed, of carets, main token of expression.
* @param midEnd Last column, 1-indexed, of carets, main token of expression.
* @param end Last column, 1-indexed, of tildes, right side of expression.
*/
extern void krk_debug_addExpression(KrkCodeObject * codeobject, uint8_t start, uint8_t midStart, uint8_t midEnd, uint8_t end);
/**
* @brief Extract expression mapping from chunk.
* @memberof KrkCodeObject
*
* Searches the debug information for the requested instruction to find
* an expression mapping and extracts the column values for underlining.
*
* @param codeobject Codeobject containing the instruction.
* @param start First column, 1-indexed, of tildes, left side of expression.
* @param midStart First column, 1-indexed, of carets, main token of expression.
* @param midEnd Last column, 1-indexed, of carets, main token of expression.
* @param end Last column, 1-indexed, of tildes, right side of expression.
* @param instruction Offset of the last byte of an opcode, as is stored in a traceback entry.
* @returns Non-zero if a mapping was found.
*/
extern int krk_debug_expressionUnderline(const KrkCodeObject * codeobject, uint8_t * start, uint8_t * midStart, uint8_t * endStart, uint8_t * end, size_t instruction);
/**
* @brief Print a value without calling the VM.
* @memberof KrkValue
*
* Print a string representation of 'value' to the stream 'f',
* avoiding calls to managed code by using simplified representations
* where necessary. This is intended for use in debugging code, such
* as during disassembly, or when printing values in an untrusted context.
*
* @note This function will truncate long strings and print them in a form
* closer to the 'repr()' representation, with escaped bytes, rather
* than directly printing them to the stream.
*
* @param f Stream to write to.
* @param value Value to display.
*/
extern void krk_printValueSafe(FILE * f, KrkValue value);
#endif

View File

@ -11,24 +11,37 @@
typedef int64_t krk_integer_type;
#ifndef _WIN32
# define PATH_SEP "/"
# ifndef STATIC_ONLY
# define KRK_PATH_SEP "/"
# ifndef KRK_STATIC_ONLY
# include <dlfcn.h>
# define dlRefType void *
# define dlSymType void *
# define dlOpen(fileName) dlopen(fileName, RTLD_NOW)
# define dlSym(dlRef, handlerName) dlsym(dlRef,handlerName)
# define dlClose(dlRef) dlclose(dlRef)
# define krk_dlRefType void *
# define krk_dlSymType void *
# define krk_dlOpen(fileName) dlopen(fileName, RTLD_NOW)
# define krk_dlSym(dlRef, handlerName) dlsym(dlRef,handlerName)
# define krk_dlClose(dlRef) dlclose(dlRef)
# endif
#else
# include <windows.h>
# define PATH_SEP "\\"
# ifndef STATIC_ONLY
# define dlRefType HINSTANCE
# define dlSymType FARPROC
# define dlOpen(fileName) LoadLibraryA(fileName)
# define dlSym(dlRef, handlerName) GetProcAddress(dlRef, handlerName)
# define dlClose(dlRef)
# define KRK_PATH_SEP "\\"
# ifndef KRK_STATIC_ONLY
# define krk_dlRefType HINSTANCE
# define krk_dlSymType FARPROC
# define krk_dlOpen(fileName) LoadLibraryA(fileName)
# define krk_dlSym(dlRef, handlerName) GetProcAddress(dlRef, handlerName)
# define krk_dlClose(dlRef)
# endif
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#define KRK_NO_DOCUMENTATION 1
#define KRK_NO_GC_TRACING 1
typedef intptr_t ssize_t;
#pragma warning(disable : 4146) /* unary minus on unsigned */
#pragma warning(disable : 4996) /* sterror */
#pragma warning(disable : 4267) /* conversions to smaller types... */
#pragma warning(disable : 4244) /* conversions to smaller types... */
#include <math.h>
#define __builtin_floor floor
#define __builtin_unreachable abort
#define __builtin_expect(cond,expected) (cond)
#endif

View File

@ -7,13 +7,10 @@
#include "object.h"
#include "table.h"
#define GROW_CAPACITY(c) ((c) < 8 ? 8 : (c) * 2)
#define GROW_ARRAY(t,p,o,n) (t*)krk_reallocate(p,sizeof(t)*o,sizeof(t)*n)
#define FREE_ARRAY(t,a,c) krk_reallocate(a,sizeof(t) * c, 0)
#define FREE(t,p) krk_reallocate(p,sizeof(t),0)
#define ALLOCATE(type, count) (type*)krk_reallocate(NULL,0,sizeof(type)*(count))
#define KRK_GROW_CAPACITY(c) ((c) < 8 ? 8 : (c) * 2)
#define KRK_GROW_ARRAY(t,p,o,n) (t*)krk_reallocate(p,sizeof(t)*o,sizeof(t)*n)
#define KRK_FREE_ARRAY(t,a,c) krk_reallocate(a,sizeof(t) * c, 0)
#define KRK_ALLOCATE(type, count) (type*)krk_reallocate(NULL,0,sizeof(type)*(count))
/**
* @brief Resize an allocated heap object.

View File

@ -133,8 +133,27 @@ typedef struct {
KrkString * name; /**< @brief Name of the local */
} KrkLocalEntry;
/**
* @brief Map entry of opcode offsets to expressions spans.
*
* Used for printing tracebacks with underlined expressions.
*/
typedef struct {
uint32_t bytecodeOffset;
uint8_t start;
uint8_t midStart;
uint8_t midEnd;
uint8_t end;
} KrkExpressionsMap;
struct KrkInstance;
typedef struct {
uint32_t instructionOffset; /**< @brief Instruction (operand offset) this jump target applies to */
uint16_t intendedTarget; /**< @brief High bytes of the intended target. */
uint8_t originalOpcode; /**< @brief Original jump opcode to execute. */
} KrkOverlongJump;
/**
* @brief Code object.
* @extends KrkObj
@ -145,8 +164,8 @@ typedef struct {
KrkObj obj; /**< @protected @brief Base */
unsigned short requiredArgs; /**< @brief Arity of required (non-default) arguments */
unsigned short keywordArgs; /**< @brief Arity of keyword (default) arguments */
unsigned short potentialPositionals;
unsigned short totalArguments;
unsigned short potentialPositionals; /**< @brief Precalculated positional arguments for complex argument processing */
unsigned short totalArguments; /**< @brief Total argument cells we can fill in complex argument processing */
size_t upvalueCount; /**< @brief Number of upvalues this function collects as a closure */
KrkChunk chunk; /**< @brief Bytecode data */
KrkString * name; /**< @brief Name of the function */
@ -157,6 +176,13 @@ typedef struct {
size_t localNameCount; /**< @brief Number of entries in @ref localNames */
KrkLocalEntry * localNames; /**< @brief Stores the names of local variables used in the function, for debugging */
KrkString * qualname; /**< @brief The dotted name of the function */
size_t expressionsCapacity; /**< @brief Capacity of @ref expressions */
size_t expressionsCount; /**< @brief Number of entries in @ref expressions */
KrkExpressionsMap * expressions; /**< @brief Mapping of bytecode offsets to expression spans for debugging */
KrkValue jumpTargets; /**< @brief Possibly a set of jump targets... */
KrkOverlongJump * overlongJumps; /**< @brief Pessimal overlong jump container */
size_t overlongJumpsCapacity; /**< @brief Number of possible entries in pessimal jump table */
size_t overlongJumpsCount; /**< @brief Number of entries in pessimal jump table */
} KrkCodeObject;
@ -188,11 +214,11 @@ typedef void (*KrkCleanupCallback)(struct KrkInstance *);
*/
typedef struct KrkClass {
KrkObj obj; /**< @protected @brief Base */
struct KrkClass * _class; /**< @brief Metaclass */
KrkTable methods; /**< @brief General attributes table */
KrkString * name; /**< @brief Name of the class */
KrkString * filename; /**< @brief Filename of the original source that defined the codeobject for the class */
KrkString * docstring; /**< @brief Storage for the class's docstring */
struct KrkClass * base; /**< @brief Pointer to base class implementation */
KrkTable methods; /**< @brief General attributes table */
size_t allocSize; /**< @brief Size to allocate when creating instances of this class */
KrkCleanupCallback _ongcscan; /**< @brief C function to call when the garbage collector visits an instance of this class in the scan phase */
KrkCleanupCallback _ongcsweep; /**< @brief C function to call when the garbage collector is discarding an instance of this class */
@ -238,6 +264,8 @@ typedef struct KrkClass {
KrkObj * _pos;
KrkObj * _setattr;
KrkObj * _format;
KrkObj * _new;
KrkObj * _bool;
size_t cacheIndex;
} KrkClass;
@ -356,8 +384,8 @@ struct DictValues {
*/
struct KrkModule {
KrkInstance inst;
#ifndef STATIC_ONLY
dlRefType libHandle;
#ifndef KRK_STATIC_ONLY
krk_dlRefType libHandle;
#endif
};

View File

@ -111,6 +111,8 @@ 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,9 +26,11 @@ typedef struct {
* @brief Simple hash table of arbitrary keys to values.
*/
typedef struct {
size_t count;
size_t capacity;
KrkTableEntry * entries;
size_t count; /**< Number of actual items in the dict. */
size_t capacity; /**< Size (in items) of each of the entries/indexes arrays */
size_t used; /**< Next insertion index in the entries array */
KrkTableEntry * entries; /**< Key-value pairs, in insertion order (with KWARGS_VAL(0) gaps) */
ssize_t * indexes; /**< Actual hash map: indexes into the key-value pairs. */
} KrkTable;
/**
@ -153,21 +155,6 @@ extern int krk_tableDelete(KrkTable * table, KrkValue key);
*/
extern int krk_tableDeleteExact(KrkTable * table, KrkValue key);
/**
* @brief Internal table scan function.
* @memberof KrkTable
*
* Scans through the the entry array 'entries' to find the appropriate entry
* for 'key', return a pointer to the entry, which may be or may not have
* an associated pair.
*
* @param entries Table entry array to scan.
* @param capacity Size of the table entry array, in entries.
* @param key Key to locate.
* @return A pointer to the entry for 'key'.
*/
extern KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue key);
/**
* @brief Calculate the hash for a value.
* @memberof KrkValue

View File

@ -33,6 +33,30 @@
#define _noexport
#endif
#if __has_attribute(unused)
# define _unused __attribute__((unused))
#else
# define _unused
#endif
#if __has_attribute(hot)
# define _hot __attribute__((hot))
#else
# define _hot
#endif
#if __has_attribute(cold)
# define _cold __attribute__((cold))
#else
# define _cold
#endif
#if __has_attribute(nonnull)
# define _nonnull __attribute__((nonnull))
#else
# define _nonnull
#endif
#define ADD_BASE_CLASS(obj, name, baseClass) krk_makeClass(vm.builtins, &obj, name, baseClass)
#define ATTRIBUTE_NOT_ASSIGNABLE() do { if (unlikely(argc != 1)) return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", \
@ -70,29 +94,31 @@
#define CHECK_ARG(i, type, ctype, name) \
if (unlikely(argc < (i+1))) return NOT_ENOUGH_ARGS(name); \
if (unlikely(!IS_ ## type (argv[i]))) return TYPE_ERROR(type,argv[i]); \
ctype name __attribute__((unused)) = AS_ ## type (argv[i])
ctype name _unused = AS_ ## type (argv[i])
#define FUNC_NAME(klass, name) _ ## klass ## _ ## name
#define FUNC_SIG(klass, name) _noexport KrkValue FUNC_NAME(klass,name) (int argc, const KrkValue argv[], int hasKw)
/* These forms are deprecated. */
#define KRK_METHOD(klass, name, ...) FUNC_SIG(klass, name) { \
static __attribute__ ((unused)) const char* _method_name = # name; \
CHECK_ARG(0,klass,CURRENT_CTYPE,CURRENT_NAME); \
__VA_ARGS__ \
return NONE_VAL(); }
#define KRK_FUNC(name,...) static KrkValue _krk_ ## name (int argc, const KrkValue argv[], int hasKw) { \
static __attribute__ ((unused)) const char* _method_name = # name; \
__VA_ARGS__ \
return NONE_VAL(); }
/* This assumes you have a KrkInstance called `module` in the current scope. */
#define MAKE_CLASS(klass) do { krk_makeClass(module,&klass,#klass,vm.baseClasses->objectClass); klass ->allocSize = sizeof(struct klass); } while (0)
#define BIND_METHOD(klass,method) krk_defineNative(&klass->methods, #method, _ ## klass ## _ ## method)
#define BIND_PROP(klass,method) krk_defineNativeProperty(&klass->methods, #method, _ ## klass ## _ ## method)
#define BIND_FUNC(module,func) krk_defineNative(&module->fields, #func, _krk_ ## func)
static inline KrkNative * krk_defineNativeStaticMethod(KrkTable * table, const char * name, NativeFn function) {
KrkNative * out = krk_defineNative(table,name,function);
out->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
return out;
}
#define BIND_STATICMETHOD(klass,method) krk_defineNativeStaticMethod(&klass->methods, #method, _ ## klass ## _ ## method)
static inline KrkNative * krk_defineNativeClassMethod(KrkTable * table, const char * name, NativeFn function) {
KrkNative * out = krk_defineNative(table,name,function);
out->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
return out;
}
#define BIND_CLASSMETHOD(klass,method) krk_defineNativeClassMethod(&klass->methods, #method, _ ## klass ## _ ## method)
#define KRK_Method_internal_name(klass, name) \
_krk_method_ ## klass ## _ ## name
#define KRK_Method_internal_sig(klass, name) \
@ -120,6 +146,16 @@
} \
KRK_Function_internal_sig(name)
#define KRK_StaticMethod_internal_sig(klass, name) \
static inline KrkValue KRK_Method_internal_name(klass, name) (const char * _method_name, int argc, const KrkValue argv[], int hasKw)
#define KRK_StaticMethod(klass, name) \
KRK_StaticMethod_internal_sig(klass, name); \
FUNC_SIG(klass, name) { \
static const char * _method_name = # name; \
return KRK_Method_internal_name(klass,name)(_method_name,argc,argv,hasKw); \
} \
KRK_StaticMethod_internal_sig(klass,name)
/**
* @brief Inline flexible string array.
*/
@ -240,7 +276,7 @@ extern KrkValue FUNC_NAME(str,format)(int,const KrkValue*,int);
#define krk_string_format FUNC_NAME(str,format)
static inline void _setDoc_class(KrkClass * thing, const char * text, size_t size) {
thing->docstring = krk_copyString(text, size);
krk_attachNamedObject(&thing->methods, "__doc__", (KrkObj*)krk_copyString(text, size));
}
static inline void _setDoc_instance(KrkInstance * thing, const char * text, size_t size) {
krk_attachNamedObject(&thing->fields, "__doc__", (KrkObj*)krk_copyString(text, size));
@ -328,4 +364,19 @@ extern int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char *
extern int krk_pushStringBuilderFormat(struct StringBuilder * sb, const char * fmt, ...);
extern KrkValue krk_stringFromFormat(const char * fmt, ...);
extern int krk_long_to_int(KrkValue val, char size, void * out);
extern int krk_isSubClass(const KrkClass * cls, const KrkClass * base);
#define KRK_Module_internal_name(name) \
_krk_module_onload_ ## name
#define KRK_Module_internal_sig(name) \
static inline void KRK_Module_internal_name(name) (KrkInstance * module, KrkString * runAs)
#define KRK_Module(name) \
KRK_Module_internal_sig(name); \
KrkValue krk_module_onload_ ## name (KrkString * runAs) { \
KrkInstance * module = krk_newInstance(KRK_BASE_CLASS(module)); \
krk_push(OBJECT_VAL(module)); \
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)runAs); \
KRK_Module_internal_name(name)(module, runAs); \
return krk_pop(); \
} \
KRK_Module_internal_sig(name)

View File

@ -7,6 +7,7 @@
#include <string.h>
#include "kuroko.h"
#ifndef KRK_NO_NAN_BOXING
/**
* @brief Tag enum for basic value types.
*
@ -23,28 +24,6 @@ typedef enum {
KRK_VAL_NOTIMPL = 0x7FFE,
} KrkValueType;
/*
* The following poorly-named macros define bit patterns for identifying
* various boxed types.
*
* Boxing is done by first setting all of the bits of MASK_NAN. If all of
* these bits are set, a value is not a float. If any of them are not set,
* then a value is a float - and possibly a real NaN.
*
* Three other bits - one before and two after the MASK_NAN bits - determine
* what type the value actually is. KWARGS sets none of the identifying bits,
* NONE sets all of them.
*/
#define KRK_VAL_MASK_BOOLEAN ((uint64_t)0xFFFC000000000000) /* 1..1100 */
#define KRK_VAL_MASK_INTEGER ((uint64_t)0xFFFD000000000000) /* 1..1101 */
#define KRK_VAL_MASK_HANDLER ((uint64_t)0xFFFE000000000000) /* 1..1110 */
#define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000) /* 1..1111 */
#define KRK_VAL_MASK_KWARGS ((uint64_t)0x7FFC000000000000) /* 0..1100 */
#define KRK_VAL_MASK_OBJECT ((uint64_t)0x7FFD000000000000) /* 0..1101 */
#define KRK_VAL_MASK_NOTIMPL ((uint64_t)0x7FFE000000000000) /* 0..1110 */
#define KRK_VAL_MASK_NAN ((uint64_t)0x7FFC000000000000)
#define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)
/**
* @struct KrkValue
* @brief Stack reference or primative value.
@ -61,6 +40,32 @@ typedef enum {
*/
typedef uint64_t KrkValue;
#define _krk_valuesSame(a,b) (a == b)
#else
/*
* Tagged union, but without the union fun.
*/
typedef enum {
KRK_VAL_NONE = 0,
KRK_VAL_INTEGER = 1,
KRK_VAL_BOOLEAN = 2,
KRK_VAL_HANDLER = 4,
KRK_VAL_KWARGS = 8,
KRK_VAL_OBJECT = 16,
KRK_VAL_NOTIMPL = 32,
KRK_VAL_FLOATING = 64,
} KrkValueType;
typedef struct {
uint64_t tag;
uint64_t val;
} KrkValue;
#define _krk_valuesSame(a,b) (memcmp(&(a),&(b),sizeof(KrkValue)) == 0)
#endif
/**
* @brief Flexible vector of stack references.
*
@ -110,42 +115,6 @@ extern void krk_writeValueArray(KrkValueArray * array, KrkValue value);
*/
extern void krk_freeValueArray(KrkValueArray * array);
/**
* @brief Print a string representation of a value.
* @memberof KrkValue
*
* Print a string representation of 'value' to the stream 'f'.
* For primitives, performs appropriate formatting. For objects,
* this will call __str__ on the object's representative type.
* If the type does not have a __str__ method, __repr__ will be
* tried before falling back to krk_typeName to directly print
* the name of the class with no information on the value.
*
* This function provides the backend for the print() built-in.
*
* @param f Stream to write to.
* @param value Value to display.
*/
extern void krk_printValue(FILE * f, KrkValue value);
/**
* @brief Print a value without calling the VM.
* @memberof KrkValue
*
* Print a string representation of 'value' to the stream 'f',
* avoiding calls to managed code by using simplified representations
* where necessary. This is intended for use in debugging code, such
* as during disassembly, or when printing values in an untrusted context.
*
* @note This function will truncate long strings and print them in a form
* closer to the 'repr()' representation, with escaped bytes, rather
* than directly printing them to the stream.
*
* @param f Stream to write to.
* @param value Value to display.
*/
extern void krk_printValueSafe(FILE * f, KrkValue value);
/**
* @brief Compare two values for equality.
* @memberof KrkValue
@ -169,7 +138,7 @@ extern int krk_valuesEqual(KrkValue a, KrkValue b);
*
* @return 1 if values represent the same object or value, 0 otherwise.
*/
extern int krk_valuesSame(KrkValue a, KrkValue b);
static inline int krk_valuesSame(KrkValue a, KrkValue b) { return _krk_valuesSame(a,b); }
/**
* @brief Compare two values by identity, then by equality.
@ -182,12 +151,37 @@ extern int krk_valuesSame(KrkValue a, KrkValue b);
extern int krk_valuesSameOrEqual(KrkValue a, KrkValue b);
extern KrkValue krk_parse_int(const char * start, size_t width, unsigned int base);
extern KrkValue krk_parse_float(const char* start, size_t width);
#ifndef KRK_NO_NAN_BOXING
typedef union {
KrkValue val;
double dbl;
} KrkValueDbl;
/*
* The following poorly-named macros define bit patterns for identifying
* various boxed types.
*
* Boxing is done by first setting all of the bits of MASK_NAN. If all of
* these bits are set, a value is not a float. If any of them are not set,
* then a value is a float - and possibly a real NaN.
*
* Three other bits - one before and two after the MASK_NAN bits - determine
* what type the value actually is. KWARGS sets none of the identifying bits,
* NONE sets all of them.
*/
#define KRK_VAL_MASK_BOOLEAN ((uint64_t)0xFFFC000000000000) /* 1..1100 */
#define KRK_VAL_MASK_INTEGER ((uint64_t)0xFFFD000000000000) /* 1..1101 */
#define KRK_VAL_MASK_HANDLER ((uint64_t)0xFFFE000000000000) /* 1..1110 */
#define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000) /* 1..1111 */
#define KRK_VAL_MASK_KWARGS ((uint64_t)0x7FFC000000000000) /* 0..1100 */
#define KRK_VAL_MASK_OBJECT ((uint64_t)0x7FFD000000000000) /* 0..1101 */
#define KRK_VAL_MASK_NOTIMPL ((uint64_t)0x7FFE000000000000) /* 0..1110 */
#define KRK_VAL_MASK_NAN ((uint64_t)0x7FFC000000000000)
#define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)
#ifdef KRK_SANITIZE_OBJECT_POINTERS
/**
* Debugging tool for verifying we aren't trying to box NULL, which is not a valid object.
@ -213,13 +207,13 @@ static inline uintptr_t _krk_sanitize(uintptr_t input) {
#define KRK_HEAP_TAG 0
#endif
#define NONE_VAL(value) ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NONE))
#define NOTIMPL_VAL(value) ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NOTIMPL))
#define NONE_VAL() ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NONE))
#define NOTIMPL_VAL() ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NOTIMPL))
#define BOOLEAN_VAL(value) ((KrkValue)(((uint64_t)(value) & KRK_VAL_MASK_LOW) | KRK_VAL_MASK_BOOLEAN))
#define INTEGER_VAL(value) ((KrkValue)(((uint64_t)(value) & KRK_VAL_MASK_LOW) | KRK_VAL_MASK_INTEGER))
#define KWARGS_VAL(value) ((KrkValue)((uint32_t)(value) | KRK_VAL_MASK_KWARGS))
#define OBJECT_VAL(value) ((KrkValue)((_krk_sanitize((uintptr_t)(value)) & KRK_VAL_MASK_LOW) | KRK_VAL_MASK_OBJECT))
#define HANDLER_VAL(ty,ta) ((KrkValue)((uint32_t)((((uint16_t)ty) << 16) | ((uint16_t)ta)) | KRK_VAL_MASK_HANDLER))
#define HANDLER_VAL(ty,ta) ((KrkValue)((uint64_t)((((uint64_t)ty) << 32) | ((uint32_t)ta)) | KRK_VAL_MASK_HANDLER))
#define FLOATING_VAL(value) (((KrkValueDbl){.dbl = (value)}).val)
#define KRK_VAL_TYPE(value) ((value) >> 48)
@ -230,7 +224,7 @@ static inline uintptr_t _krk_sanitize(uintptr_t input) {
#define AS_BOOLEAN(value) AS_INTEGER(value)
#define AS_NOTIMPL(value) ((krk_integer_type)((value) & KRK_VAL_MASK_LOW))
#define AS_HANDLER(value) ((uint32_t)((value) & KRK_VAL_MASK_LOW))
#define AS_HANDLER(value) ((uint64_t)((value) & KRK_VAL_MASK_LOW))
#define AS_OBJECT(value) ((KrkObj*)(uintptr_t)(((value) & KRK_VAL_MASK_LOW) | KRK_HEAP_TAG))
#define AS_FLOATING(value) (((KrkValueDbl){.val = (value)}).dbl)
@ -249,8 +243,49 @@ static inline uintptr_t _krk_sanitize(uintptr_t input) {
/* ... and as we said above, if any of the MASK_NAN bits are unset, it's a float. */
#define IS_FLOATING(value) (((value) & KRK_VAL_MASK_NAN) != KRK_VAL_MASK_NAN)
#define AS_HANDLER_TYPE(value) (AS_HANDLER(value) >> 16)
#define AS_HANDLER_TARGET(value) (AS_HANDLER(value) & 0xFFFF)
#else
typedef union {
uint64_t val;
double dbl;
} KrkValueDbl;
#define NONE_VAL() ((KrkValue){KRK_VAL_NONE,-1})
#define NOTIMPL_VAL() ((KrkValue){KRK_VAL_NOTIMPL,0})
#define BOOLEAN_VAL(value) ((KrkValue){KRK_VAL_BOOLEAN,!!(value)})
#define INTEGER_VAL(value) ((KrkValue){KRK_VAL_INTEGER,((uint64_t)(value)) & 0xFFFFffffFFFFULL})
#define KWARGS_VAL(value) ((KrkValue){KRK_VAL_KWARGS,((uint32_t)(value))})
#define OBJECT_VAL(value) ((KrkValue){KRK_VAL_OBJECT,((uintptr_t)(value))})
#define HANDLER_VAL(ty,ta) ((KrkValue){KRK_VAL_HANDLER,((uint64_t)((((uint64_t)ty) << 32) | ((uint32_t)ta)))})
#define FLOATING_VAL(value) ((KrkValue){KRK_VAL_FLOATING,(((KrkValueDbl){.dbl = (value)}).val)})
#define KRK_VAL_TYPE(value) ((value).tag)
#define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000)
#define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)
#define KRK_IX(value) ((uint64_t)((value).val & KRK_VAL_MASK_LOW))
#define KRK_SX(value) ((uint64_t)((value).val & 0x800000000000))
#define AS_INTEGER(value) ((krk_integer_type)(KRK_SX(value) ? (KRK_IX(value) | KRK_VAL_MASK_NONE) : (KRK_IX(value))))
#define AS_BOOLEAN(value) AS_INTEGER(value)
#define AS_HANDLER(value) ((uint64_t)((value)).val)
#define AS_OBJECT(value) ((KrkObj*)((uintptr_t)((value).val)))
#define AS_FLOATING(value) (((KrkValueDbl){.val = ((value)).val}).dbl)
#define IS_INTEGER(value) (!!(((value)).tag & (KRK_VAL_INTEGER|KRK_VAL_BOOLEAN)))
#define IS_BOOLEAN(value) (((value)).tag == KRK_VAL_BOOLEAN)
#define IS_NONE(value) (((value)).tag == KRK_VAL_NONE)
#define IS_HANDLER(value) (((value)).tag == KRK_VAL_HANDLER)
#define IS_OBJECT(value) (((value)).tag == KRK_VAL_OBJECT)
#define IS_KWARGS(value) (((value)).tag == KRK_VAL_KWARGS)
#define IS_NOTIMPL(value) (((value)).tag == KRK_VAL_NOTIMPL)
#define IS_FLOATING(value) (((value)).tag == KRK_VAL_FLOATING)
#endif
#define AS_HANDLER_TYPE(value) (AS_HANDLER(value) >> 32)
#define AS_HANDLER_TARGET(value) (AS_HANDLER(value) & 0xFFFFFFFF)
#define IS_HANDLER_TYPE(value,type) (IS_HANDLER(value) && AS_HANDLER_TYPE(value) == type)
#define KWARGS_SINGLE (INT32_MAX)

View File

@ -7,9 +7,7 @@
* for Kuroko, including initializing the VM and passing code to be interpreted.
*/
#include <stdarg.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
#include "kuroko.h"
#include "value.h"
#include "table.h"
@ -19,7 +17,7 @@
* @def KRK_CALL_FRAMES_MAX
* @brief Maximum depth of the call stack in managed-code function calls.
*/
#define KRK_CALL_FRAMES_MAX 64
#define KRK_CALL_FRAMES_MAX 1000
/**
* @def KRK_THREAD_SCRATCH_SIZE
@ -50,9 +48,6 @@ typedef struct {
size_t outSlots; /**< Offset into the stack at which stackTop will be reset upon return */
KrkTable * globals; /**< Pointer to the attribute table containing valud global vairables for this call */
KrkValue globalsOwner; /**< Owner of the current globals context, to give to new closures. */
#ifndef KRK_NO_CALLGRIND
struct timespec in_time;
#endif
} KrkCallFrame;
/**
@ -136,16 +131,13 @@ struct BaseClasses {
KrkClass * enumerateClass; /**< Yield pairs of indexes and values from an iterator. */
KrkClass * HelperClass; /**< Class implementation of 'help' object */
KrkClass * LicenseReaderClass; /**< Class implementation of 'license' object */
KrkClass * FileClass; /**< os.File */
KrkClass * BinaryFileClass; /**< os.BinaryFile */
KrkClass * DirectoryClass; /**< os.Directory */
KrkClass * stat_resultClass; /**< stat.stat_result */
KrkClass * EnvironClass; /**< os._Environ */
KrkClass * CompilerStateClass; /**< Compiler global state */
KrkClass * CellClass; /**< Upvalue cell */
KrkClass * setClass; /**< Unordered hashset */
KrkClass * setiteratorClass; /**< Iterator over values in a set */
KrkClass * ThreadClass; /**< Threading.Thread */
KrkClass * LockClass; /**< Threading.Lock */
KrkClass * CompilerStateClass; /**< Compiler global state */
KrkClass * ellipsisClass; /**< Type of the Ellipsis (...) singleton */
};
/**
@ -171,6 +163,7 @@ typedef struct KrkThreadState {
KrkInstance * module; /**< The current module execution context. */
KrkValue currentException; /**< When an exception is thrown, it is stored here. */
int flags; /**< Thread-local VM flags; each thread inherits the low byte of the global VM flags. */
unsigned int maximumCallDepth; /**< Maximum recursive call depth. */
KrkValue * stackMax; /**< End of allocated stack space. */
KrkValue scratchSpace[KRK_THREAD_SCRATCH_SIZE]; /**< A place to store a few values to keep them from being prematurely GC'd. */
@ -204,8 +197,6 @@ typedef struct KrkVM {
KrkObj** grayStack; /**< Scan list */
KrkThreadState * threads; /**< Invasive linked list of all VM threads. */
FILE * callgrindFile; /**< File to write unprocessed callgrind data to. */
size_t maximumCallDepth; /**< Maximum recursive call depth. */
struct DebuggerState * dbgState; /**< Opaque debugger state pointer. */
} KrkVM;
@ -222,15 +213,15 @@ typedef struct KrkVM {
#define KRK_GLOBAL_ENABLE_STRESS_GC (1 << 8)
#define KRK_GLOBAL_GC_PAUSED (1 << 9)
#define KRK_GLOBAL_CLEAN_OUTPUT (1 << 10)
#define KRK_GLOBAL_CALLGRIND (1 << 11)
/* 11 is available again */
#define KRK_GLOBAL_REPORT_GC_COLLECTS (1 << 12)
#define KRK_GLOBAL_THREADS (1 << 13)
#define KRK_GLOBAL_NO_DEFAULT_MODULES (1 << 14)
#ifndef KRK_DISABLE_THREADS
# define threadLocal __thread
# define krk_threadLocal __thread
#else
# define threadLocal
# define krk_threadLocal
#endif
/**
@ -251,7 +242,7 @@ inline KrkThreadState * _macos_currentThread(void) {
#elif !defined(KRK_DISABLE_THREADS) && ((defined(_WIN32) && !defined(KRKINLIB)) || defined(KRK_MEDIOCRE_TLS))
#define krk_currentThread (*krk_getCurrentThread())
#else
extern threadLocal KrkThreadState krk_currentThread;
extern krk_threadLocal KrkThreadState krk_currentThread;
#endif
/**
@ -320,7 +311,7 @@ extern void krk_resetStack(void);
* indicate @c KRK_THREAD_HAS_EXCEPTION and @c krk_currentThread.currentException
* should contain the raised exception value.
*/
extern KrkValue krk_interpret(const char * src, char * fromFile);
extern KrkValue krk_interpret(const char * src, const char * fromFile);
/**
* @brief Load and run a source file and return when execution completes.
@ -334,7 +325,7 @@ extern KrkValue krk_interpret(const char * src, char * fromFile);
* @return As with @c krk_interpret, an object representing the newly created module,
* or the final return value of the VM execution.
*/
extern KrkValue krk_runfile(const char * fileName, char * fromFile);
extern KrkValue krk_runfile(const char * fileName, const char * fromFile);
/**
* @brief Push a stack value.
@ -596,10 +587,12 @@ extern int krk_isInstanceOf(KrkValue obj, const KrkClass * type);
* @memberof KrkClass
*
* Performs attribute lookup from the class @p _class for @p name.
* If @p name is not a valid method, the binding fails.
* If @p name is not a valid member, the binding fails.
* If @p name is a valid method, the method will be retrieved and
* bound to the instance on the top of the stack, replacing it
* with a @ref BoundMethod object.
* If @p name is not a method, the unbound attribute is returned.
* If @p name is a descriptor, the @c %__get__ method is executed.
*
* @param _class Class object to resolve methods from.
* @param name String object with the name of the method to resolve.
@ -607,6 +600,22 @@ extern int krk_isInstanceOf(KrkValue obj, const KrkClass * type);
*/
extern int krk_bindMethod(KrkClass * _class, KrkString * name);
/**
* @brief Bind a method with super() semantics
* @memberof KrkClass
*
* @see krk_bindMethod
*
* Allows binding potential class methods with the correct class object while
* searching from a base class. Used by the @c super() mechanism.
*
* @param baseClass The superclass to begin searching from.
* @param name The name of the member to look up.
* @param realClass The class to bind if a class method is found.
* @return 1 if a member has been found, 0 if binding fails.
*/
extern int krk_bindMethodSuper(KrkClass * baseClass, KrkString * name, KrkClass * realClass);
/**
* @brief Call a callable value in the current stack context.
* @memberof KrkValue
@ -976,33 +985,6 @@ extern int krk_delAttribute(KrkString * name);
*/
extern void krk_module_init_kuroko(void);
/**
* @brief Initialize the built-in 'gc' module.
*/
extern void krk_module_init_gc(void);
/**
* @brief Initialize the built-in 'time' module.
*/
extern void krk_module_init_time(void);
/**
* @brief Initialize the built-in 'os' module.
*/
extern void krk_module_init_os(void);
/**
* @brief Initialize the built-in 'fileio' module.
*/
extern void krk_module_init_fileio(void);
/**
* @brief Initialize the built-in 'dis' module.
*
* Not available if KRK_DISABLE_DEBUG is set.
*/
extern void krk_module_init_dis(void);
/**
* @brief Initialize the built-in 'threading' module.
*

View File

@ -1,3 +1,4 @@
#include <time.h>
#include <kuroko/vm.h>
#include <kuroko/memory.h>
#include <kuroko/object.h>
@ -7,6 +8,8 @@
#include "private.h"
#define FREE_OBJECT(t,p) krk_reallocate(p,sizeof(t),0)
#if defined(KRK_EXTENSIVE_MEMORY_DEBUGGING)
/**
* Extensive Memory Debugging
@ -18,7 +21,7 @@
* the sizes of objects by both using the appropriate macros and by
* ensuring the right sizes are passed to those macros. This is a very
* easy thing to get wrong - allocate with @c malloc but free with the
* @c FREE_ARRAY macros, for example, and the memory tracking now has
* @c KRK_FREE_ARRAY macros, for example, and the memory tracking now has
* a net negative, which may lead to underflowing. Use the right macros,
* but mix up sizes between allocation and deallocation, and we may have
* a "leak" of bytes and garbage collection may happen more often than
@ -202,9 +205,9 @@ static void freeObject(KrkObj * object) {
switch (object->type) {
case KRK_OBJ_STRING: {
KrkString * string = (KrkString*)object;
FREE_ARRAY(char, string->chars, string->length + 1);
KRK_FREE_ARRAY(char, string->chars, string->length + 1);
if (string->codes && string->codes != string->chars) free(string->codes);
FREE(KrkString, object);
FREE_OBJECT(KrkString, object);
break;
}
case KRK_OBJ_CODEOBJECT: {
@ -212,24 +215,26 @@ static void freeObject(KrkObj * object) {
krk_freeChunk(&function->chunk);
krk_freeValueArray(&function->positionalArgNames);
krk_freeValueArray(&function->keywordArgNames);
FREE_ARRAY(KrkLocalEntry, function->localNames, function->localNameCount);
KRK_FREE_ARRAY(KrkLocalEntry, function->localNames, function->localNameCount);
KRK_FREE_ARRAY(KrkExpressionsMap, function->expressions, function->expressionsCapacity);
KRK_FREE_ARRAY(KrkOverlongJump, function->overlongJumps, function->overlongJumpsCapacity);
function->localNameCount = 0;
FREE(KrkCodeObject, object);
FREE_OBJECT(KrkCodeObject, object);
break;
}
case KRK_OBJ_NATIVE: {
FREE(KrkNative, object);
FREE_OBJECT(KrkNative, object);
break;
}
case KRK_OBJ_CLOSURE: {
KrkClosure * closure = (KrkClosure*)object;
FREE_ARRAY(KrkUpvalue*,closure->upvalues,closure->upvalueCount);
KRK_FREE_ARRAY(KrkUpvalue*,closure->upvalues,closure->upvalueCount);
krk_freeTable(&closure->fields);
FREE(KrkClosure, object);
FREE_OBJECT(KrkClosure, object);
break;
}
case KRK_OBJ_UPVALUE: {
FREE(KrkUpvalue, object);
FREE_OBJECT(KrkUpvalue, object);
break;
}
case KRK_OBJ_CLASS: {
@ -239,7 +244,7 @@ static void freeObject(KrkObj * object) {
if (_class->base) {
krk_tableDeleteExact(&_class->base->subclasses, OBJECT_VAL(object));
}
FREE(KrkClass, object);
FREE_OBJECT(KrkClass, object);
break;
}
case KRK_OBJ_INSTANCE: {
@ -252,24 +257,24 @@ static void freeObject(KrkObj * object) {
break;
}
case KRK_OBJ_BOUND_METHOD:
FREE(KrkBoundMethod, object);
FREE_OBJECT(KrkBoundMethod, object);
break;
case KRK_OBJ_TUPLE: {
KrkTuple * tuple = (KrkTuple*)object;
krk_freeValueArray(&tuple->values);
FREE(KrkTuple, object);
FREE_OBJECT(KrkTuple, object);
break;
}
case KRK_OBJ_BYTES: {
KrkBytes * bytes = (KrkBytes*)object;
FREE_ARRAY(uint8_t, bytes->bytes, bytes->length);
FREE(KrkBytes, bytes);
KRK_FREE_ARRAY(uint8_t, bytes->bytes, bytes->length);
FREE_OBJECT(KrkBytes, bytes);
break;
}
}
}
void krk_freeObjects() {
void krk_freeObjects(void) {
KrkObj * object = vm.objects;
KrkObj * other = NULL;
@ -319,7 +324,7 @@ void krk_markObject(KrkObj * object) {
object->flags |= KRK_OBJ_FLAGS_IS_MARKED;
if (vm.grayCapacity < vm.grayCount + 1) {
vm.grayCapacity = GROW_CAPACITY(vm.grayCapacity);
vm.grayCapacity = KRK_GROW_CAPACITY(vm.grayCapacity);
vm.grayStack = realloc(vm.grayStack, sizeof(KrkObj*) * vm.grayCapacity);
if (!vm.grayStack) exit(1);
}
@ -362,6 +367,7 @@ static void blackenObject(KrkObj * object) {
for (size_t i = 0; i < function->localNameCount; ++i) {
krk_markObject((KrkObj*)function->localNames[i].name);
}
krk_markValue(function->jumpTargets);
break;
}
case KRK_OBJ_UPVALUE:
@ -371,8 +377,8 @@ static void blackenObject(KrkObj * object) {
KrkClass * _class = (KrkClass *)object;
krk_markObject((KrkObj*)_class->name);
krk_markObject((KrkObj*)_class->filename);
krk_markObject((KrkObj*)_class->docstring);
krk_markObject((KrkObj*)_class->base);
krk_markObject((KrkObj*)_class->_class);
krk_markTable(&_class->methods);
break;
}
@ -436,7 +442,7 @@ static size_t sweep(void) {
}
void krk_markTable(KrkTable * table) {
for (size_t i = 0; i < table->capacity; ++i) {
for (size_t i = 0; i < table->used; ++i) {
KrkTableEntry * entry = &table->entries[i];
krk_markValue(entry->key);
krk_markValue(entry->value);
@ -444,7 +450,7 @@ void krk_markTable(KrkTable * table) {
}
static void tableRemoveWhite(KrkTable * table) {
for (size_t i = 0; i < table->capacity; ++i) {
for (size_t i = 0; i < table->used; ++i) {
KrkTableEntry * entry = &table->entries[i];
if (IS_OBJECT(entry->key) && !((AS_OBJECT(entry->key))->flags & KRK_OBJ_FLAGS_IS_MARKED)) {
krk_tableDeleteExact(table, entry->key);
@ -562,42 +568,3 @@ size_t krk_collectGarbage(void) {
return out;
}
#ifndef KRK_NO_SYSTEM_MODULES
KRK_Function(collect) {
FUNCTION_TAKES_NONE();
if (&krk_currentThread != vm.threads) return krk_runtimeError(vm.exceptions->valueError, "only the main thread can do that");
return INTEGER_VAL(krk_collectGarbage());
}
KRK_Function(pause) {
FUNCTION_TAKES_NONE();
vm.globalFlags |= (KRK_GLOBAL_GC_PAUSED);
return NONE_VAL();
}
KRK_Function(resume) {
FUNCTION_TAKES_NONE();
vm.globalFlags &= ~(KRK_GLOBAL_GC_PAUSED);
return NONE_VAL();
}
void krk_module_init_gc(void) {
/**
* gc = module()
*
* Namespace for methods for controlling the garbage collector.
*/
KrkInstance * gcModule = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "gc", (KrkObj*)gcModule);
krk_attachNamedObject(&gcModule->fields, "__name__", (KrkObj*)S("gc"));
krk_attachNamedValue(&gcModule->fields, "__file__", NONE_VAL());
KRK_DOC(gcModule, "@brief Namespace containing methods for controlling the garbage collector.");
KRK_DOC(BIND_FUNC(gcModule,collect),
"@brief Triggers one cycle of garbage collection.");
KRK_DOC(BIND_FUNC(gcModule,pause),
"@brief Disables automatic garbage collection until @ref resume is called.");
KRK_DOC(BIND_FUNC(gcModule,resume),
"@brief Re-enable automatic garbage collection after it was stopped by @ref pause ");
}
#endif

View File

@ -17,6 +17,7 @@ CACHED_METHOD(DESCGET, "__get__", _descget)
CACHED_METHOD(DESCSET, "__set__", _descset)
CACHED_METHOD(CLASSGETITEM, "__class_getitem__", _classgetitem)
CACHED_METHOD(HASH, "__hash__", _hash)
CACHED_METHOD(BOOL, "__bool__", _bool)
#define BINOPTRIO(name) \
CACHED_METHOD(name, "__" #name "__", _ ## name) \
@ -47,6 +48,7 @@ CACHED_METHOD(SETNAME, "__set_name__", _set_name)
CACHED_METHOD(POS, "__pos__", _pos)
CACHED_METHOD(SETATTR, "__setattr__", _setattr)
CACHED_METHOD(FORMAT, "__format__", _format)
CACHED_METHOD(NEW, "__new__", _new)
/* These are not methods */
SPECIAL_ATTRS(CLASS, "__class__")
@ -60,4 +62,10 @@ SPECIAL_ATTRS(CHR, "__chr__")
SPECIAL_ATTRS(ORD, "__ord__")
SPECIAL_ATTRS(FLOAT, "__float__")
SPECIAL_ATTRS(STRSTRIP, " \t\n\r")
SPECIAL_ATTRS(HEX, "__hex__")
SPECIAL_ATTRS(OCT, "__oct__")
SPECIAL_ATTRS(BIN, "__bin__")
SPECIAL_ATTRS(ABS, "__abs__")
SPECIAL_ATTRS(FUNC, "__func__")
SPECIAL_ATTRS(BLDCLS, "__build_class__")
SPECIAL_ATTRS(MAIN, "__main__")

315
src/modules/module__pheap.c Normal file
View File

@ -0,0 +1,315 @@
/**
* @brief Pairing heap.
* @file module__pheap.c
* @author K. Lange <klange@toaruos.org>
*
* A very simple pairing heap.
*
* Provides a min-heap with insert, peek, and pop.
*
* While heap entries may be mutable, care should be taken not to modify
* any values used for comparison, as the heap can not update ordering.
*
* This could likely be improved by the implementation of parent pointers,
* which can allow for elements of the heap other than the root to be
* removed or updated (removal + reinsertion), but that requires the
* ability to quickly reference specific elements - which requires the
* heap "nodes" to also be accessible or addressible in some way, such
* as by making them Kuroko objects. Such a change would likely result
* in performance impacts, so a parent-pointer pairing heap should be
* a separate class.
*
* The implementation here is based strongly on the pseudocode found in
* the Wikipedia article "Paring heap".
*/
#include <assert.h>
#include <stdlib.h>
#include <kuroko/vm.h>
#include <kuroko/util.h>
static KrkClass * PHeapClass;
/**
* @brief Heap node.
*
* Represents one element in the heap. Each element potentially has
* a pointer to more elements (a "right" or "next" pointer) and a
* pointer to a subheap (a "left" pointer).
*/
typedef struct PHeap PHeap;
struct PHeap {
struct PHeap_Obj * owner;
KrkValue value;
PHeap * subheaps; /* Left pointer to first child, if any. */
PHeap * next; /* Right pointer to next sibling, if any. */
};
/**
* @brief Heap comparator function.
*
* The heap is ostensibly a min-heap, but the comparison behavior is left
* entirely to the user. A comparator function should return true if the
* left (first) argument has priority (is less than) the right (second)
* argument, and 0 otherwise. This comparison must be consistent or the
* heap will not work correctly.
*
* Generally, this module only uses one comparison function: a wrapper that
* calls a Kuroko callable. As Kuroko callables may hold their own state,
* no facility was necessary to pass user data to the comparator - only
* the left and right heap nodes to compare are given.
*/
typedef int (*pheap_comparator_func)(PHeap *, PHeap *);
/**
* @brief meld - Combine two heaps.
*
* Combines two heaps and returns the result. The heaps are "destroyed" in the process.
*
* @param left One heap. Can be @c NULL for an empty heap.
* @param right The other heap. Can be @c NULL for an empty heap.
* @param comparator Function that should return true if @p left has priority (is less than) @p right.
* @returns A pointer to the new root, which will be either of @p left or @p right.
*/
static PHeap * pheap_meld(PHeap * left, PHeap * right, pheap_comparator_func comparator) {
/*
* If either of the heaps is "empty" (represented by NULL),
* then simply return the other one.
*/
if (!left) {
return right;
}
if (!right) {
return left;
}
/*
* Otherwise, pull the 'smaller' of the two up and add the 'larger'
* to the front of the subheap list of the smaller one. We use
* intrusive lists within our Heap struct, so each Heap is also
* a List node (with a `next` pointer).
*/
if (comparator(left, right)) {
/* Turns `left` into Heap(left→value, right :: left→subheaps) */
if (left->subheaps) {
right->next = left->subheaps;
}
left->subheaps = right;
return left;
} else {
/* Turns `right` into Heap(right→value, left :: right→subheaps) */
if (right->subheaps) {
left->next = right->subheaps;
}
right->subheaps = left;
return right;
}
}
/**
* @brief merge_pairs - Perform left-to-right/right-to-left merge on lists of subheaps.
*
* The core of the heap.
*
* @param list List of pairs to merge.
* @param comparator Comparator function as described in @c pheap_meld.
* @returns the resulting heap.
*/
static PHeap * pheap_merge_pairs(PHeap * list, pheap_comparator_func comparator) {
if (!list) {
/* An empty list is represented by NULL, and yields an empty Heap,
* which is also represented by NULL... */
return NULL;
} else if (list->next == NULL) {
/* If a list entry doesn't have a next, it has a size of one,
* and we can just return this heap directly. */
return list;
} else {
/* Otherwise we meld the first two, then meld them with the result of
* recursively melding the rest, which performs our left-right /
* right-left two-stage merge. */
PHeap * next = list->next;
list->next = NULL;
PHeap * rest = next->next;
next->next = NULL;
return pheap_meld(pheap_meld(list, next, comparator), pheap_merge_pairs(rest, comparator), comparator);
}
}
/**
* @brief delete_min - Remove the 'smallest' value from the heap.
*
* Removes the root node of the heap, rebalancing the remainder
* of the heap. Should only be used when the heap is not empty.
*
* @param heap Heap to remove the root of.
* @param comparator Comparator function as described in @c pheap_meld.
* @returns the resulting heap.
*/
static PHeap * pheap_delete_min(PHeap * heap, pheap_comparator_func comparator) {
PHeap * subs = heap->subheaps;
return pheap_merge_pairs(subs, comparator);
}
/**
* @brief visit_heap - Call a user function for every node in the heap.
*
* The function is called before recursing.
*
* @param heap Heap to walk.
* @param func Function to call.
* @param extra User data to pass to the function.
*/
static void pheap_visit_heap(PHeap * heap, void (*func)(PHeap *, void*), void* extra) {
if (!heap) return;
func(heap, extra);
pheap_visit_heap(heap->subheaps, func, extra);
pheap_visit_heap(heap->next, func, extra);
}
/**
* @brief visit_heap_after - Call a user function for every node in the heap.
*
* The function is called after recursing, so this is suitable for freeing the
* entirety of a heap.
*
* @param heap Heap to walk.
* @param func Function to call.
* @param extra User data to pass to the function.
*/
static void pheap_visit_heap_after(PHeap * heap, void (*func)(PHeap *, void*), void* extra) {
if (!heap) return;
pheap_visit_heap_after(heap->subheaps, func, extra);
pheap_visit_heap_after(heap->next, func, extra);
func(heap, extra);
}
struct PHeap_Obj {
KrkInstance inst;
KrkValue comparator;
PHeap * heap;
size_t count;
};
#define IS_PHeap(o) (krk_isInstanceOf(o,PHeapClass))
#define AS_PHeap(o) ((struct PHeap_Obj*)AS_OBJECT(o))
#define CURRENT_CTYPE struct PHeap_Obj *
#define CURRENT_NAME self
KRK_Method(PHeap,__init__) {
KrkValue comparator;
if (!krk_parseArgs(".V:PHeap", (const char*[]){"comp"}, &comparator)) return NONE_VAL();
self->comparator = comparator;
return NONE_VAL();
}
static int run_comparator(PHeap * left, PHeap * right) {
assert(left->owner == right->owner);
krk_push(left->owner->comparator);
krk_push(left->value);
krk_push(right->value);
KrkValue result = krk_callStack(2);
if (!IS_BOOLEAN(result)) return 0;
return AS_BOOLEAN(result);
}
KRK_Method(PHeap,insert) {
KrkValue value;
if (!krk_parseArgs(".V",(const char*[]){"value"}, &value)) return NONE_VAL();
struct PHeap * node = calloc(sizeof(struct PHeap), 1);
node->owner = self;
node->value = value;
self->heap = pheap_meld(self->heap, node, run_comparator);
self->count += 1;
return NONE_VAL();
}
KRK_Method(PHeap,peek) {
if (self->heap) return self->heap->value;
return NONE_VAL();
}
KRK_Method(PHeap,pop) {
PHeap * old = self->heap;
if (!old) return krk_runtimeError(vm.exceptions->indexError, "pop from empty heap");
self->heap = pheap_delete_min(self->heap, run_comparator);
self->count -= 1;
KrkValue out = old->value;
free(old);
return out;
}
KRK_Method(PHeap,__bool__) {
return BOOLEAN_VAL(self->heap != NULL);
}
KRK_Method(PHeap,__len__) {
return INTEGER_VAL(self->count);
}
static void run_visitor(PHeap * heap, void * visitor) {
krk_push(*(KrkValue*)visitor);
krk_push(heap->value);
krk_callStack(1);
}
KRK_Method(PHeap,visit) {
KrkValue func;
int after = 0;
if (!krk_parseArgs(".V|p",(const char*[]){"func","after"},
&func, &after)) return NONE_VAL();
(after ? pheap_visit_heap_after : pheap_visit_heap)(self->heap, run_visitor, &func);
return NONE_VAL();
}
static void _scan_one(PHeap * heap, void * unused) {
krk_markValue(heap->value);
}
static void _pheap_scan(KrkInstance * _self) {
struct PHeap_Obj * self = (void*)_self;
krk_markValue(self->comparator);
pheap_visit_heap(self->heap, _scan_one, NULL);
}
static void _free_one(PHeap * heap, void * unused) {
free(heap);
}
static void _pheap_sweep(KrkInstance * _self) {
struct PHeap_Obj * self = (void*)_self;
pheap_visit_heap_after(self->heap,_free_one, NULL);
}
KRK_Method(PHeap,comp) {
return self->comparator;
}
KRK_Module(_pheap) {
KRK_DOC(module, "Pairing heap with simple insert and pop-min operations.");
KrkClass * PHeap = krk_makeClass(module, &PHeapClass, "PHeap", vm.baseClasses->objectClass);
KRK_DOC(PHeap,"Pairing heap with simple insert and pop-min operations.");
PHeap->allocSize = sizeof(struct PHeap_Obj);
PHeap->_ongcscan = _pheap_scan;
PHeap->_ongcsweep = _pheap_sweep;
KRK_DOC(BIND_METHOD(PHeap,__init__),
"@arguments comp\n\n"
"Create a new pairing heap governed by the given comparator function.");
KRK_DOC(BIND_METHOD(PHeap,insert),
"@arguments value\n\n"
"Insert a new element into the heap.");
KRK_DOC(BIND_METHOD(PHeap,peek),
"Retrieve the root (smallest) element of the heap, or None if it is empty.");
KRK_DOC(BIND_METHOD(PHeap,pop),
"Remove and return the root (smallest) element of the heap. If the heap is empty, IndexError is raised.");
BIND_METHOD(PHeap,__bool__);
BIND_METHOD(PHeap,__len__);
KRK_DOC(BIND_METHOD(PHeap,visit),
"@arguments func,after=False\n\n"
"Call a function for each element of the heap.");
BIND_PROP(PHeap,comp);
krk_finalizeClass(PHeapClass);
}

376
src/modules/module_dis.c Normal file
View File

@ -0,0 +1,376 @@
#include <stdio.h>
#include <string.h>
#include <kuroko/debug.h>
#include <kuroko/vm.h>
#include <kuroko/util.h>
#include <kuroko/compiler.h>
#include "../private.h"
#include "../opcode_enum.h"
#ifndef KRK_DISABLE_DEBUG
KRK_Function(enablebreakpoint) {
int breakIndex;
if (!krk_parseArgs("i",(const char*[]){"breakpoint"}, &breakIndex)) return NONE_VAL();
if (krk_debug_enableBreakpoint(breakIndex))
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
return NONE_VAL();
}
KRK_Function(disablebreakpoint) {
int breakIndex;
if (!krk_parseArgs("i",(const char*[]){"breakpoint"}, &breakIndex)) return NONE_VAL();
if (krk_debug_disableBreakpoint(breakIndex))
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
return NONE_VAL();
}
KRK_Function(delbreakpoint) {
int breakIndex;
if (!krk_parseArgs("i",(const char*[]){"breakpoint"}, &breakIndex)) return NONE_VAL();
if (krk_debug_removeBreakpoint(breakIndex))
return krk_runtimeError(vm.exceptions->indexError, "invalid breakpoint id");
return NONE_VAL();
}
KRK_Function(addbreakpoint) {
KrkValue func;
int lineNo;
int flags = KRK_BREAKPOINT_NORMAL;
if (!krk_parseArgs("Vi|i",(const char*[]){"func","lineno","flags"}, &func, &lineNo, &flags)) return NONE_VAL();
int result;
if (IS_STRING(func)) {
result = krk_debug_addBreakpointFileLine(AS_STRING(func), lineNo, flags);
} else {
KrkCodeObject * target = NULL;
if (IS_CLOSURE(func)) {
target = AS_CLOSURE(func)->function;
} else if (IS_BOUND_METHOD(func) && IS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(func)->method))) {
target = AS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(func)->method))->function;
} else if (IS_codeobject(func)) {
target = AS_codeobject(func);
} else {
return TYPE_ERROR(function or method or filename,func);
}
/* Figure out what instruction this should be on */
size_t last = 0;
for (size_t i = 0; i < target->chunk.linesCount; ++i) {
if (target->chunk.lines[i].line > (size_t)lineNo) break;
if (target->chunk.lines[i].line == (size_t)lineNo) {
last = target->chunk.lines[i].startOffset;
break;
}
last = target->chunk.lines[i].startOffset;
}
result = krk_debug_addBreakpointCodeOffset(target,last,flags);
}
if (result < 0)
return krk_runtimeError(vm.exceptions->baseException, "Could not add breakpoint.");
return INTEGER_VAL(result);
}
/**
* dis.dis(object)
*/
KRK_Function(dis) {
KrkValue funcVal;
if (!krk_parseArgs("V",(const char*[]){"func"},&funcVal)) return NONE_VAL();
if (IS_CLOSURE(funcVal)) {
KrkCodeObject * func = AS_CLOSURE(funcVal)->function;
krk_disassembleCodeObject(stdout, func, func->name ? func->name->chars : "<unnamed>");
} else if (IS_codeobject(funcVal)) {
krk_disassembleCodeObject(stdout, AS_codeobject(funcVal), AS_codeobject(funcVal)->name ? AS_codeobject(funcVal)->name->chars : "<unnamed>");
} else if (IS_BOUND_METHOD(funcVal)) {
if (AS_BOUND_METHOD(funcVal)->method->type == KRK_OBJ_CLOSURE) {
KrkCodeObject * func = ((KrkClosure*)AS_BOUND_METHOD(funcVal)->method)->function;
const char * methodName = func->name ? func->name->chars : "<unnamed>";
const char * typeName = IS_CLASS(AS_BOUND_METHOD(funcVal)->receiver) ? AS_CLASS(AS_BOUND_METHOD(funcVal)->receiver)->name->chars : krk_typeName(AS_BOUND_METHOD(funcVal)->receiver);
size_t allocSize = strlen(methodName) + strlen(typeName) + 2;
char * tmp = malloc(allocSize);
snprintf(tmp, allocSize, "%s.%s", typeName, methodName);
krk_disassembleCodeObject(stdout, func, tmp);
free(tmp);
} else {
krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%T'", AS_BOUND_METHOD(funcVal)->receiver);
}
} else if (IS_CLASS(funcVal)) {
KrkValue code;
if (krk_tableGet(&AS_CLASS(funcVal)->methods, vm.specialMethodNames[METHOD_FUNC], &code) && IS_CLOSURE(code)) {
KrkCodeObject * func = AS_CLOSURE(code)->function;
krk_disassembleCodeObject(stdout, func, AS_CLASS(funcVal)->name->chars);
}
/* TODO Methods! */
} else {
krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%T'", funcVal);
}
return NONE_VAL();
}
KRK_Function(build) {
char * code;
char * fileName = "<source>";
if (!krk_parseArgs("s|s", (const char*[]){"code","filename"}, &code, &fileName)) return NONE_VAL();
/* Unset module */
krk_push(OBJECT_VAL(krk_currentThread.module));
KrkInstance * module = krk_currentThread.module;
krk_currentThread.module = NULL;
KrkCodeObject * c = krk_compile(code,fileName);
krk_currentThread.module = module;
krk_pop();
if (c) return OBJECT_VAL(c);
else return NONE_VAL();
}
#define NOOP (void)0
#define SIMPLE(opc) case opc: size = 1; break;
#define CONSTANT(opc,more) case opc: { constant = chunk->code[offset + 1]; size = 2; more; break; } \
case opc ## _LONG: { constant = (chunk->code[offset + 1] << 16) | \
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
#define OPERAND(opc,more) case opc: { operand = chunk->code[offset + 1]; size = 2; more; break; } \
case opc ## _LONG: { operand = (chunk->code[offset + 1] << 16) | \
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
#define JUMP(opc,sign) case opc: { jump = 0 sign ((chunk->code[offset + 1] << 8) | (chunk->code[offset + 2])); \
size = 3; break; }
#define COMPLICATED(opc,more) case opc: size = 1; more; break;
#define OVERLONG_JUMP_MORE size = 3; jump = (chunk->code[offset + 1] << 8) | (chunk->code[offset + 2])
#define CLOSURE_MORE \
KrkCodeObject * function = AS_codeobject(chunk->constants.values[constant]); \
size_t baseOffset = offset; \
for (size_t j = 0; j < function->upvalueCount; ++j) { \
int isLocal = chunk->code[baseOffset++ + size]; \
baseOffset++; \
if (isLocal & 2) { \
baseOffset += 2; \
} \
} \
size += baseOffset - offset;
#define EXPAND_ARGS_MORE
#define FORMAT_VALUE_MORE
#define LOCAL_MORE local = operand;
static KrkValue _examineInternal(KrkCodeObject* func) {
KrkValue output = krk_list_of(0,NULL,0);
krk_push(output);
KrkChunk * chunk = &func->chunk;
size_t offset = 0;
while (offset < chunk->count) {
uint8_t opcode = chunk->code[offset];
size_t size = 0;
ssize_t constant = -1;
ssize_t jump = 0;
ssize_t operand = -1;
ssize_t local = -1;
switch (opcode) {
#include "opcodes.h"
}
KrkTuple * newTuple = krk_newTuple(3);
krk_push(OBJECT_VAL(newTuple));
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(opcode);
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(size);
if (constant != -1) {
newTuple->values.values[newTuple->values.count++] = chunk->constants.values[constant];
} else if (jump != 0) {
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(jump);
} else if (local != -1) {
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand); /* Just in case */
for (size_t i = 0; i < func->localNameCount; ++i) {
if (func->localNames[i].id == (size_t)local && func->localNames[i].birthday <= offset && func->localNames[i].deathday >= offset) {
newTuple->values.values[newTuple->values.count-1] = OBJECT_VAL(func->localNames[i].name);
break;
}
}
} else if (operand != -1) {
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand);
} else {
newTuple->values.values[newTuple->values.count++] = NONE_VAL();
}
krk_writeValueArray(AS_LIST(output), krk_peek(0));
krk_pop();
if (size == 0) {
abort();
}
offset += size;
}
return krk_pop();
}
KRK_Function(examine) {
KrkCodeObject * func;
if (!krk_parseArgs("O!",(const char*[]){"func"}, KRK_BASE_CLASS(codeobject), &func)) return NONE_VAL();
return _examineInternal(func);
}
#undef SIMPLE
#undef OPERANDB
#undef OPERAND
#undef CONSTANT
#undef JUMP
#undef COMPLICATED
#undef OVERLONG_JUMP_MORE
#undef CLOSURE_MORE
#undef LOCAL_MORE
#undef EXPAND_ARGS_MORE
#undef FORMAT_VALUE_MORE
KRK_Function(ip_to_expression) {
KrkValue func;
size_t ip;
if (!krk_parseArgs("VN",(const char*[]){"func","ip"}, &func, &ip)) return NONE_VAL();
KrkCodeObject * actual;
if (IS_CLOSURE(func)) actual = AS_CLOSURE(func)->function;
else if (IS_codeobject(func)) actual = AS_codeobject(func);
else if (IS_BOUND_METHOD(func) && IS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(func)->method))) actual = ((KrkClosure*)AS_BOUND_METHOD(func)->method)->function;
else return krk_runtimeError(vm.exceptions->typeError, "func must be a managed function, method, or codeobject, not '%T'", func);
int lineNo = krk_lineNumber(&actual->chunk, ip);
uint8_t start, midStart, midEnd, end;
if (krk_debug_expressionUnderline(actual, &start, &midStart, &midEnd, &end, ip)) {
KrkTuple * out = krk_newTuple(5);
krk_push(OBJECT_VAL(out));
out->values.values[out->values.count++] = INTEGER_VAL(lineNo);
out->values.values[out->values.count++] = INTEGER_VAL(start);
out->values.values[out->values.count++] = INTEGER_VAL(midStart);
out->values.values[out->values.count++] = INTEGER_VAL(midEnd);
out->values.values[out->values.count++] = INTEGER_VAL(end);
return krk_pop();
}
return NONE_VAL();
}
#endif
KRK_Module(dis) {
#ifndef KRK_DISABLE_DEBUG
KRK_DOC(module,
"@brief Provides tools for disassembling bytecode.\n\n"
"### Code Disassembly in Kuroko\n\n"
"The @c dis module contains functions for dealing with _code objects_ which "
"represent the compiled bytecode of a Kuroko function. The bytecode compilation "
"process is entirely static and bytecode analysis can be performed without calling "
"into the VM to run dynamic code.\n\n"
"### Debugger Breakpoints\n\n"
"Kuroko interpreters can provide a debugger hook through the C API's "
"@ref krk_debug_registerCallback() function. Breakpoints can be managed both "
"from the C API and from this module's @ref addbreakpoint, @ref delbreakpoint, "
"@ref enablebreakpoint, and @ref disablebreakpoint methods."
);
KRK_DOC(BIND_FUNC(module, dis),
"@brief Disassemble an object.\n"
"@arguments obj\n\n"
"Dumps a disassembly of the bytecode in the code object associated with @p obj. "
"If @p obj can not be disassembled, a @ref TypeError is raised.");
KRK_DOC(BIND_FUNC(module, build),
"@brief Compile a string to a code object.\n"
"@arguments code\n\n"
"Compiles the string @p code and returns a code object. If a syntax "
"error is encountered, it will be raised.");
KRK_DOC(BIND_FUNC(module, examine),
"@brief Convert a code object to a list of instructions.\n"
"@arguments func\n\n"
"Examines the code object @p func and returns a list representation of its instructions. "
"Each instruction entry is a tuple of the opcode, total instruction size in bytes, and "
"the operand of the argument, either as an integer for jump offsets, the actual value for "
"constant operands, or the name of a local or global variable if available.");
KRK_DOC(BIND_FUNC(module, addbreakpoint),
"@brief Attach a breakpoint to a code object.\n"
"@arguments func, line\n\n"
"@p func may be a filename string, or a function, method, or code object. Returns "
"the new breakpoint index, or raises @ref Exception if a breakpoint code not be added.");
KRK_DOC(BIND_FUNC(module, delbreakpoint),
"@brief Delete a breakpoint.\n"
"@arguments handle\n\n"
"Delete the breakpoint specified by @p handle, disabling it if it was enabled. "
"May raise @ref IndexError if @p handle is not a valid breakpoint handle.");
KRK_DOC(BIND_FUNC(module, enablebreakpoint),
"@brief Enable a breakpoint.\n"
"@arguments handle\n\n"
"Enable the breakpoint specified by @p handle. May raise @ref IndexError if "
"@p handle is not a valid breakpoint handle.");
KRK_DOC(BIND_FUNC(module, disablebreakpoint),
"@brief Disable a breakpoint.\n"
"@arguments handle\n\n"
"Disable the breakpoint specified by @p handle. May raise @ref IndexError if "
"@p handle is not a valid breakpoint handle.");
KRK_DOC(BIND_FUNC(module, ip_to_expression),
"@brief Map an IP in a codeobject or function to an expression span.\n"
"@arguments func,ip\n\n"
"For various reasons, the instruction pointer @p ip must be the last byte of an opcode.");
krk_attachNamedValue(&module->fields, "BREAKPOINT_ONCE", INTEGER_VAL(KRK_BREAKPOINT_ONCE));
krk_attachNamedValue(&module->fields, "BREAKPOINT_REPEAT", INTEGER_VAL(KRK_BREAKPOINT_REPEAT));
#define OPCODE(opc) krk_attachNamedValue(&module->fields, #opc, INTEGER_VAL(opc));
#define SIMPLE(opc) OPCODE(opc)
#define CONSTANT(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
#define OPERAND(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
#define JUMP(opc,sign) OPCODE(opc)
#define COMPLICATED(opc,more) OPCODE(opc)
#include "opcodes.h"
#undef SIMPLE
#undef OPERANDB
#undef OPERAND
#undef CONSTANT
#undef JUMP
#undef COMPLICATED
if (runAs && !strcmp(runAs->chars,"__main__")) {
/* Force `dis` into the module table early */
krk_attachNamedObject(&vm.modules, "dis", (KrkObj*)module);
/* Start executing additional code */
krk_startModule("_dis");
krk_interpret(
"import dis\n"
"def disrec(code, seen):\n"
" let next = [code]\n"
" while next:\n"
" let co = next[0]\n"
" next = next[1:]\n"
" dis.dis(co)\n"
" for inst,size,operand in dis.examine(co):\n"
" if isinstance(operand,codeobject) and operand not in seen and operand not in next:\n"
" next.append(operand)\n"
" if next:\n"
" print()\n"
"import kuroko\n"
"if (len(kuroko.argv) < 2):\n"
" print(\"Usage: kuroko -m dis FILE\")\n"
" return 1\n"
"import fileio\n"
"for file in kuroko.argv[1:]:\n"
" with fileio.open(file,'r') as f:\n"
" let result = dis.build(f.read(), file)\n"
" disrec(result,set())\n",
"_dis"
);
}
#else
krk_runtimeError(vm.exceptions->notImplementedError, "debugger support is disabled");
#endif
}

View File

@ -14,6 +14,11 @@
#include <kuroko/memory.h>
#include <kuroko/util.h>
static KrkClass * fileio_File;
static KrkClass * fileio_BinaryFile;
static KrkClass * fileio_Directory;
/**
* @brief Object for a C `FILE*` stream.
* @extends KrkInstance
@ -24,10 +29,10 @@ struct File {
int unowned;
};
#define IS_File(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(File)))
#define IS_File(o) (krk_isInstanceOf(o, fileio_File))
#define AS_File(o) ((struct File*)AS_OBJECT(o))
#define IS_BinaryFile(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(BinaryFile)))
#define IS_BinaryFile(o) (krk_isInstanceOf(o, fileio_BinaryFile))
#define AS_BinaryFile(o) ((struct File*)AS_OBJECT(o))
/**
@ -39,7 +44,7 @@ struct Directory {
DIR * dirPtr;
};
#define IS_Directory(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(Directory)))
#define IS_Directory(o) (krk_isInstanceOf(o, fileio_Directory))
#define AS_Directory(o) ((struct Directory*)AS_OBJECT(o))
#define CURRENT_CTYPE struct File *
@ -77,7 +82,7 @@ KRK_Function(open) {
if (!file) return krk_runtimeError(vm.exceptions->ioError, "open: failed to open file; system returned: %s", strerror(errno));
/* Now let's build an object to hold it */
KrkInstance * fileObject = krk_newInstance(isBinary ? KRK_BASE_CLASS(BinaryFile) : KRK_BASE_CLASS(File));
KrkInstance * fileObject = krk_newInstance(isBinary ? fileio_BinaryFile : fileio_File);
krk_push(OBJECT_VAL(fileObject));
/* Let's put the filename in there somewhere... */
@ -93,7 +98,7 @@ KRK_Function(open) {
#define BLOCK_SIZE 1024
KRK_Method(File,__str__) {
KRK_Method(File,__repr__) {
METHOD_TAKES_NONE();
KrkValue filename;
KrkValue modestr;
@ -259,7 +264,7 @@ KRK_Method(File,__exit__) {
}
static void makeFileInstance(KrkInstance * module, const char name[], FILE * file, const char mode[]) {
KrkInstance * fileObject = krk_newInstance(KRK_BASE_CLASS(File));
KrkInstance * fileObject = krk_newInstance(fileio_File);
krk_push(OBJECT_VAL(fileObject));
KrkValue filename = OBJECT_VAL(krk_copyString(name,strlen(name)));
krk_push(filename);
@ -433,7 +438,7 @@ KRK_Function(opendir) {
DIR * dir = opendir(path->chars);
if (!dir) return krk_runtimeError(vm.exceptions->ioError, "opendir: %s", strerror(errno));
struct Directory * dirObj = (void *)krk_newInstance(KRK_BASE_CLASS(Directory));
struct Directory * dirObj = (void *)krk_newInstance(fileio_Directory);
krk_push(OBJECT_VAL(dirObj));
krk_attachNamedValue(&dirObj->inst.fields, "path", OBJECT_VAL(path));
@ -489,11 +494,7 @@ KRK_Method(Directory,__exit__) {
return FUNC_NAME(Directory,close)(1,argv,0);
}
void krk_module_init_fileio(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "fileio", (KrkObj*)module);
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("fileio"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
KRK_Module(fileio) {
KRK_DOC(module,
"@brief Provides access to C <stdio> buffered file I/O functions.\n\n"
"The @c fileio module provides classes and functions for reading "
@ -502,7 +503,7 @@ void krk_module_init_fileio(void) {
);
/* Define a class to represent files. (Should this be a helper method?) */
KrkClass * File = krk_makeClass(module, &KRK_BASE_CLASS(File), "File", KRK_BASE_CLASS(object));
KrkClass * File = krk_makeClass(module, &fileio_File, "File", KRK_BASE_CLASS(object));
KRK_DOC(File,"Interface to a buffered file stream.");
File->allocSize = sizeof(struct File);
File->_ongcsweep = _file_sweep;
@ -519,15 +520,14 @@ void krk_module_init_fileio(void) {
"Writes the contents of @p data to the stream.");
KRK_DOC(BIND_METHOD(File,close), "@brief Close the stream and flush any remaining buffered writes.");
KRK_DOC(BIND_METHOD(File,flush), "@brief Flush unbuffered writes to the stream.");
BIND_METHOD(File,__str__);
BIND_METHOD(File,__repr__);
KRK_DOC(BIND_METHOD(File,__init__), "@bsnote{%File objects can not be initialized using this constructor. "
"Use the <a class=\"el\" href=\"#open\">open()</a> function instead.}");
BIND_METHOD(File,__enter__);
BIND_METHOD(File,__exit__);
krk_defineNative(&File->methods, "__repr__", FUNC_NAME(File,__str__));
krk_finalizeClass(File);
KrkClass * BinaryFile = krk_makeClass(module, &KRK_BASE_CLASS(BinaryFile), "BinaryFile", File);
KrkClass * BinaryFile = krk_makeClass(module, &fileio_BinaryFile, "BinaryFile", File);
KRK_DOC(BinaryFile,
"Equivalent to @ref File but using @ref bytes instead of string @ref str."
);
@ -537,7 +537,7 @@ void krk_module_init_fileio(void) {
BIND_METHOD(BinaryFile,write);
krk_finalizeClass(BinaryFile);
KrkClass * Directory = krk_makeClass(module, &KRK_BASE_CLASS(Directory), "Directory", KRK_BASE_CLASS(object));
KrkClass * Directory = krk_makeClass(module, &fileio_Directory, "Directory", KRK_BASE_CLASS(object));
KRK_DOC(Directory,
"Represents an opened file system directory."
);

31
src/modules/module_gc.c Normal file
View File

@ -0,0 +1,31 @@
#include <kuroko/vm.h>
#include <kuroko/util.h>
KRK_Function(collect) {
FUNCTION_TAKES_NONE();
if (&krk_currentThread != vm.threads) return krk_runtimeError(vm.exceptions->valueError, "only the main thread can do that");
return INTEGER_VAL(krk_collectGarbage());
}
KRK_Function(pause) {
FUNCTION_TAKES_NONE();
vm.globalFlags |= (KRK_GLOBAL_GC_PAUSED);
return NONE_VAL();
}
KRK_Function(resume) {
FUNCTION_TAKES_NONE();
vm.globalFlags &= ~(KRK_GLOBAL_GC_PAUSED);
return NONE_VAL();
}
KRK_Module(gc) {
KRK_DOC(module, "@brief Namespace containing methods for controlling the garbage collector.");
KRK_DOC(BIND_FUNC(module,collect),
"@brief Triggers one cycle of garbage collection.");
KRK_DOC(BIND_FUNC(module,pause),
"@brief Disables automatic garbage collection until @ref resume is called.");
KRK_DOC(BIND_FUNC(module,resume),
"@brief Re-enable automatic garbage collection after it was stopped by @ref pause ");
}

View File

@ -0,0 +1,99 @@
#include <limits.h>
#include <locale.h>
#include <kuroko/vm.h>
#include <kuroko/util.h>
KRK_Function(setlocale) {
int category;
const char * locale = NULL;
if (!krk_parseArgs("i|z",(const char*[]){"category","locale"}, &category, &locale)) return NONE_VAL();
char * result = setlocale(category, locale);
if (!result) {
return krk_runtimeError(vm.exceptions->valueError, "unsupported locale setting or query failed");
}
return OBJECT_VAL(krk_copyString(result,strlen(result)));
}
static void do_grouping(KrkValue result, const char * keyname, const char * grouping) {
KrkValue out = krk_list_of(0,NULL,0);
krk_push(out);
const char * c = grouping;
/* If there is nothing here, return an empty list, otherwise return all
* entries including either a terminating NUL or a terminating CHAR_MAX */
if (*c) {
do {
krk_writeValueArray(AS_LIST(out), INTEGER_VAL(*c));
if (!*c || *c == CHAR_MAX) break;
c++;
} while (1);
}
krk_attachNamedValue(AS_DICT(result), keyname, out);
krk_pop();
}
KRK_Function(localeconv) {
FUNCTION_TAKES_NONE();
struct lconv * lc = localeconv();
/* localeconv is defined to never fail... */
KrkValue result = krk_dict_of(0,NULL,0);
krk_push(result);
#define DO_DICT_STR(key) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)krk_copyString(lc-> key, strlen(lc-> key)))
#define DO_DICT_INT(key) krk_attachNamedValue(AS_DICT(result), #key, INTEGER_VAL(lc-> key))
DO_DICT_STR(decimal_point);
DO_DICT_STR(thousands_sep);
DO_DICT_STR(int_curr_symbol);
DO_DICT_STR(currency_symbol);
DO_DICT_STR(mon_decimal_point);
DO_DICT_STR(mon_thousands_sep);
DO_DICT_STR(positive_sign);
DO_DICT_STR(negative_sign);
DO_DICT_INT(int_frac_digits);
DO_DICT_INT(frac_digits);
DO_DICT_INT(p_cs_precedes);
DO_DICT_INT(p_sep_by_space);
DO_DICT_INT(n_cs_precedes);
DO_DICT_INT(n_sep_by_space);
DO_DICT_INT(p_sign_posn);
DO_DICT_INT(n_sign_posn);
/* 'grouping' and 'mon_grouping' aren't real strings */
do_grouping(result, "grouping", lc->grouping);
do_grouping(result, "mon_grouping", lc->mon_grouping);
#undef DO_DICT_STR
#undef DO_DICT_INT
return krk_pop();
}
KRK_Module(locale) {
KRK_DOC(module, "@brief Bindings for C locale functions");
KRK_DOC(BIND_FUNC(module,setlocale),
"@brief Set or query the C locale\n"
"@arguments category,locale=None\n\n"
"Set the locale used by various C functions.");
BIND_FUNC(module,localeconv);
#define DO_INT(name) krk_attachNamedValue(&module->fields, #name, INTEGER_VAL(name))
DO_INT(LC_ALL);
DO_INT(LC_COLLATE);
DO_INT(LC_CTYPE);
DO_INT(LC_MONETARY);
DO_INT(LC_NUMERIC);
DO_INT(LC_TIME);
/* LC_MESSAGES ? */
DO_INT(CHAR_MAX); /* Needed to understand grouping */
#undef DO_INT
}

View File

@ -38,11 +38,13 @@
return NONE_VAL(); \
}
extern KrkValue krk_int_from_float(double val);
#define MATH_DELEGATE(func) \
static KrkValue _math_ ## func(int argc, const KrkValue argv[], int hasKw) { \
ONE_ARGUMENT(func) \
if (IS_FLOATING(argv[0])) { \
return INTEGER_VAL(func(AS_FLOATING(argv[0]))); \
return krk_int_from_float(func(AS_FLOATING(argv[0]))); \
} else if (IS_INTEGER(argv[0])) { \
return argv[0]; /* no op */ \
} else { \
@ -146,10 +148,7 @@ MATH_IS(isnan)
#define bind(name) krk_defineNative(&module->fields, #name, _math_ ## name)
KrkValue krk_module_onload_math(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_push(OBJECT_VAL(module));
KRK_Module(math) {
KRK_DOC(module, "@brief Provides access to floating-point mathematical functions from the system `libm`.");
KRK_DOC(bind(ceil),
"@brief Returns the smallest integer value not less than the input.\n"
@ -269,7 +268,4 @@ KrkValue krk_module_onload_math(void) {
krk_attachNamedValue(&module->fields, "e", FLOATING_VAL(M_E));
krk_attachNamedValue(&module->fields, "inf", FLOATING_VAL(INFINITY));
krk_attachNamedValue(&module->fields, "nan", FLOATING_VAL(NAN));
krk_pop();
return OBJECT_VAL(module);
}

View File

@ -23,6 +23,9 @@
/* Did you know this is actually specified to not exist in a header? */
extern char ** environ;
static KrkClass * os_Environ;
static KrkClass * os_stat_result;
#define DO_KEY(key) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)krk_copyString(buf. key, strlen(buf .key)))
#define S_KEY(key,val) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)val);
@ -89,7 +92,7 @@ KRK_Function(uname) {
#endif
#define AS_Environ(o) (AS_INSTANCE(o))
#define IS_Environ(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(Environ)))
#define IS_Environ(o) (krk_isInstanceOf(o,os_Environ))
#define CURRENT_CTYPE KrkInstance*
static int _setVar(KrkString * key, KrkString * val) {
@ -141,7 +144,7 @@ KRK_Method(Environ,__delitem__) {
static void _loadEnviron(KrkInstance * module) {
/* Create a new class to subclass `dict` */
KrkClass * Environ = krk_makeClass(module, &KRK_BASE_CLASS(Environ), "_Environ", vm.baseClasses->dictClass);
KrkClass * Environ = krk_makeClass(module, &os_Environ, "_Environ", vm.baseClasses->dictClass);
krk_attachNamedObject(&module->fields, "_Environ", (KrkObj*)Environ);
/* Add our set method that should also call dict's set method */
@ -553,7 +556,7 @@ KRK_Function(stat) {
if (result == -1) {
return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
}
KrkInstance * out = krk_newInstance(KRK_BASE_CLASS(stat_result));
KrkInstance * out = krk_newInstance(os_stat_result);
krk_push(OBJECT_VAL(out));
SET(st_dev);
@ -571,7 +574,7 @@ KRK_Function(stat) {
}
#undef SET
#define IS_stat_result(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(stat_result)))
#define IS_stat_result(o) (krk_isInstanceOf(o,os_stat_result))
#define AS_stat_result(o) AS_INSTANCE(o)
#define CURRENT_NAME self
@ -614,49 +617,7 @@ KRK_Method(stat_result,__repr__) {
return krk_pop();
}
KRK_Function(S_ISBLK) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISBLK(mode));
}
KRK_Function(S_ISCHR) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISCHR(mode));
}
KRK_Function(S_ISDIR) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISDIR(mode));
}
KRK_Function(S_ISFIFO) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISFIFO(mode));
}
KRK_Function(S_ISREG) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISREG(mode));
}
#ifndef _WIN32
KRK_Function(S_ISLNK) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISLNK(mode));
}
KRK_Function(S_ISSOCK) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISSOCK(mode));
}
#endif
void krk_module_init_os(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "os", (KrkObj*)module);
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("os"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
KRK_Module(os) {
KRK_DOC(module, "@brief Provides access to low-level system operations.");
#ifdef _WIN32
@ -869,7 +830,7 @@ void krk_module_init_os(void) {
_loadEnviron(module);
/* Nothing special */
KrkClass * stat_result = krk_makeClass(module, &KRK_BASE_CLASS(stat_result), "stat_result", vm.baseClasses->objectClass);
KrkClass * stat_result = krk_makeClass(module, &os_stat_result, "stat_result", vm.baseClasses->objectClass);
BIND_METHOD(stat_result,__repr__);
krk_finalizeClass(stat_result);
@ -877,23 +838,6 @@ void krk_module_init_os(void) {
"@brief Get the status of a file\n"
"@arguments path\n\n"
"Runs the @c stat system call on @p path. Returns a @ref stat_result.\n");
module = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "stat", (KrkObj*)module);
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("stat"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
KRK_DOC(module,
"@brief Functions to check results from @ref stat calls.");
BIND_FUNC(module,S_ISBLK);
BIND_FUNC(module,S_ISCHR);
BIND_FUNC(module,S_ISDIR);
BIND_FUNC(module,S_ISFIFO);
BIND_FUNC(module,S_ISREG);
#ifndef _WIN32
BIND_FUNC(module,S_ISLNK);
BIND_FUNC(module,S_ISSOCK);
#endif
}

View File

@ -58,16 +58,11 @@ KRK_Function(seed) {
return NONE_VAL();
}
KrkValue krk_module_onload_random(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_push(OBJECT_VAL(module));
KRK_Module(random) {
KRK_DOC(module, "Functions for generating pseudo-random numbers.");
BIND_FUNC(module, random);
BIND_FUNC(module, seed);
FUNC_NAME(krk,seed)(0,NULL,0);
return krk_pop();
}

View File

@ -14,6 +14,9 @@
#include <arpa/inet.h>
#include <netdb.h>
#endif
#ifdef AF_UNIX
#include <sys/un.h>
#endif
#include <errno.h>
#include <kuroko/vm.h>
@ -36,27 +39,18 @@ struct socket {
#define CURRENT_CTYPE struct socket *
#define CURRENT_NAME self
#define NAMED_ARG(name,type,ctype,def,ind) \
ctype name = def; \
if (argc > ind) { \
CHECK_ARG(ind,type,ctype,_tmp); \
name = _tmp; \
} \
if (hasKw) { \
KrkValue tmp; \
if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S(#name)), &tmp)) { \
if (!IS_ ## type (tmp)) return TYPE_ERROR(type,tmp); \
name = AS_ ## type (tmp); \
} \
}
KRK_Method(socket,__init__) {
METHOD_TAKES_AT_MOST(3);
/* Complex argument processing time... */
NAMED_ARG(family,int,krk_integer_type,AF_INET,1);
NAMED_ARG(type,int,krk_integer_type,SOCK_STREAM,2);
NAMED_ARG(proto,int,krk_integer_type,0,3);
int family = AF_INET;
int type = SOCK_STREAM;
int proto = 0;
if (!krk_parseArgs(".|iii:socket",
(const char *[]){"family","type","proto"},
&family, &type, &proto)) {
return NONE_VAL();
}
int result = socket(family,type,proto);
@ -69,7 +63,7 @@ KRK_Method(socket,__init__) {
self->type = type;
self->proto = proto;
return argv[0];
return NONE_VAL();
}
static char * _af_name(int afval) {
@ -122,7 +116,7 @@ static int socket_parse_address(struct socket * self, KrkValue address, struct s
return 1;
}
if (!IS_str(addr->values.values[0])) {
krk_runtimeError(vm.exceptions->typeError, "Address should be int, not '%T'", addr->values.values[0]);
krk_runtimeError(vm.exceptions->typeError, "Address should be str, not '%T'", addr->values.values[0]);
return 1;
}
if (!IS_int(addr->values.values[1])) {
@ -171,6 +165,87 @@ static int socket_parse_address(struct socket * self, KrkValue address, struct s
return 0;
}
#ifdef AF_INET6
} else if (self->family == AF_INET6) {
/* Should be 2-tuple */
if (!IS_tuple(address)) {
krk_runtimeError(vm.exceptions->typeError, "Expected 2-tuple, not '%T'", address);
return 1;
}
KrkTuple * addr = AS_TUPLE(address);
if (addr->values.count != 2) {
krk_runtimeError(vm.exceptions->typeError, "Expected 2-tuple, not '%T'", address);
return 1;
}
if (!IS_str(addr->values.values[0])) {
krk_runtimeError(vm.exceptions->typeError, "Address should be str, not '%T'", addr->values.values[0]);
return 1;
}
if (!IS_int(addr->values.values[1])) {
krk_runtimeError(vm.exceptions->typeError, "Port should be int, not '%T'", addr->values.values[1]);
return 1;
}
if (!AS_STRING(addr->values.values[0])->length) {
struct sockaddr_in6 * sin = (struct sockaddr_in6*)sock_addr;
*sock_size = sizeof(struct sockaddr_in6);
sin->sin6_family = AF_INET6;
sin->sin6_port = htons(AS_int(addr->values.values[1]));
sin->sin6_addr = in6addr_any;
return 0;
} else {
struct addrinfo *result;
struct addrinfo *res;
int error = getaddrinfo(AS_CSTRING(addr->values.values[0]), NULL, NULL, &result);
if (error != 0) {
krk_runtimeError(SocketError, "getaddrinfo() returned error: %d", error);
return 1;
}
int found = 0;
res = result;
while (res) {
if (res->ai_family == AF_INET6) {
found = 1;
*sock_size = res->ai_addrlen;
memcpy(sock_addr, res->ai_addr, *sock_size);
break;
}
res = res->ai_next;
}
freeaddrinfo(result);
if (!found) {
krk_runtimeError(SocketError, "no suitable address");
return 1;
}
struct sockaddr_in6 * sin = (struct sockaddr_in6*)sock_addr;
sin->sin6_family = AF_INET6;
sin->sin6_port = htons(AS_int(addr->values.values[1]));
return 0;
}
#endif
#ifdef AF_UNIX
} else if (self->family == AF_UNIX) {
if (!IS_str(address)) {
krk_runtimeError(vm.exceptions->typeError, "Address should be str, not '%T'", address);
return 1;
}
if (AS_STRING(address)->length > 107) {
krk_runtimeError(vm.exceptions->valueError, "Address is too long");
return 1;
}
struct sockaddr_un * sun = (struct sockaddr_un*)sock_addr;
*sock_size = sizeof(struct sockaddr_un);
sun->sun_family = AF_UNIX;
memcpy(sun->sun_path, AS_CSTRING(address), AS_STRING(address)->length + 1);
return 0;
#endif
} else {
krk_runtimeError(vm.exceptions->notImplementedError, "Not implemented.");
return 1;
@ -266,10 +341,11 @@ KRK_Method(socket,accept) {
outTuple->values.count = 1;
krk_pop();
KrkTuple * addrTuple = krk_newTuple(2); /* TODO: Other formats */
krk_push(OBJECT_VAL(addrTuple));
if (self->family == AF_INET) {
KrkTuple * addrTuple = krk_newTuple(2); /* TODO: Other formats */
krk_push(OBJECT_VAL(addrTuple));
char hostname[NI_MAXHOST] = "";
getnameinfo((struct sockaddr*)&addr, addrlen, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
@ -277,6 +353,24 @@ KRK_Method(socket,accept) {
addrTuple->values.count = 1;
addrTuple->values.values[1] = INTEGER_VAL(htons(((struct sockaddr_in*)&addr)->sin_port));
addrTuple->values.count = 2;
#ifdef AF_INET6
} else if (self->family == AF_INET6) {
KrkTuple * addrTuple = krk_newTuple(2); /* TODO: Other formats */
krk_push(OBJECT_VAL(addrTuple));
char hostname[NI_MAXHOST] = "";
getnameinfo((struct sockaddr*)&addr, addrlen, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
addrTuple->values.values[0] = OBJECT_VAL(krk_copyString(hostname,strlen(hostname)));
addrTuple->values.count = 1;
addrTuple->values.values[1] = INTEGER_VAL(htons(((struct sockaddr_in6*)&addr)->sin6_port));
addrTuple->values.count = 2;
#endif
#ifdef AF_UNIX
} else if (self->family == AF_UNIX) {
/* ignore remote path because it's meaningless? */
krk_push(OBJECT_VAL(S("")));
#endif
} else {
krk_push(NONE_VAL());
}
@ -404,10 +498,22 @@ KRK_Function(htons) {
return INTEGER_VAL(htons(value));
}
KrkValue krk_module_onload_socket(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_push(OBJECT_VAL(module));
KRK_Method(socket,family) {
if (argc > 1) return krk_runtimeError(vm.exceptions->attributeError, "readonly attribute");
return INTEGER_VAL(self->family);
}
KRK_Method(socket,type) {
if (argc > 1) return krk_runtimeError(vm.exceptions->attributeError, "readonly attribute");
return INTEGER_VAL(self->type);
}
KRK_Method(socket,proto) {
if (argc > 1) return krk_runtimeError(vm.exceptions->attributeError, "readonly attribute");
return INTEGER_VAL(self->proto);
}
KRK_Module(socket) {
KRK_DOC(module, "Lightweight wrapper around the standard Berkeley sockets interface.");
KrkClass * socket = krk_makeClass(module, &SocketClass, "socket", vm.baseClasses->objectClass);
@ -459,7 +565,11 @@ KrkValue krk_module_onload_socket(void) {
"@arguments level,optname,value\n\n"
"@p level and @p optname should be integer values defined by @c SOL and @c SO options. "
"@p value must be either an @ref int or a @ref bytes object.");
krk_defineNative(&socket->methods,"__str__", FUNC_NAME(socket,__repr__));
BIND_PROP(socket,family);
BIND_PROP(socket,type);
BIND_PROP(socket,proto);
krk_finalizeClass(SocketClass);
BIND_FUNC(module, htons);
@ -509,6 +619,4 @@ KrkValue krk_module_onload_socket(void) {
krk_makeClass(module, &SocketError, "SocketError", vm.exceptions->baseException);
KRK_DOC(SocketError, "Raised on faults from socket functions.");
krk_finalizeClass(SocketError);
return krk_pop();
}

57
src/modules/module_stat.c Normal file
View File

@ -0,0 +1,57 @@
#include <sys/stat.h>
#include <kuroko/vm.h>
#include <kuroko/util.h>
KRK_Function(S_ISBLK) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISBLK(mode));
}
KRK_Function(S_ISCHR) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISCHR(mode));
}
KRK_Function(S_ISDIR) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISDIR(mode));
}
KRK_Function(S_ISFIFO) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISFIFO(mode));
}
KRK_Function(S_ISREG) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISREG(mode));
}
#ifndef _WIN32
KRK_Function(S_ISLNK) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISLNK(mode));
}
KRK_Function(S_ISSOCK) {
int mode;
if (!krk_parseArgs("i",(const char*[]){"mode"},&mode)) return NONE_VAL();
return INTEGER_VAL(S_ISSOCK(mode));
}
#endif
KRK_Module(stat) {
KRK_DOC(module, "@brief Functions to check results from @ref stat calls.");
BIND_FUNC(module,S_ISBLK);
BIND_FUNC(module,S_ISCHR);
BIND_FUNC(module,S_ISDIR);
BIND_FUNC(module,S_ISFIFO);
BIND_FUNC(module,S_ISREG);
#ifndef _WIN32
BIND_FUNC(module,S_ISLNK);
BIND_FUNC(module,S_ISSOCK);
#endif
}

276
src/modules/module_time.c Normal file
View File

@ -0,0 +1,276 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <kuroko/vm.h>
#include <kuroko/value.h>
#include <kuroko/object.h>
#include <kuroko/util.h>
KRK_Function(sleep) {
FUNCTION_TAKES_EXACTLY(1);
if (!IS_INTEGER(argv[0]) && !IS_FLOATING(argv[0])) {
return TYPE_ERROR(int or float,argv[0]);
}
unsigned int usecs = (IS_INTEGER(argv[0]) ? AS_INTEGER(argv[0]) :
(IS_FLOATING(argv[0]) ? AS_FLOATING(argv[0]) : 0)) *
1000000;
usleep(usecs);
return BOOLEAN_VAL(1);
}
KRK_Function(time) {
FUNCTION_TAKES_NONE();
struct timeval tv;
gettimeofday(&tv,NULL);
double out = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
return FLOATING_VAL(out);
}
static KrkClass * struct_time;
struct struct_time_obj {
KrkInstance inst;
struct tm _value;
};
#define IS_struct_time(o) (krk_isInstanceOf(o,struct_time))
#define AS_struct_time(o) ((struct struct_time_obj*)AS_OBJECT(o))
#define CURRENT_CTYPE struct struct_time_obj *
#define CURRENT_NAME self
KRK_Method(struct_time,__init__) {
KrkValue seq;
if (!krk_parseArgs(".V:struct_time", (const char *[]){"iterable"}, &seq)) return NONE_VAL();
if (!IS_TUPLE(seq) || AS_TUPLE(seq)->values.count != 9) return krk_runtimeError(vm.exceptions->notImplementedError, "sequence other than 9-tuple unsupported");
for (int i = 0; i < 9; ++i) {
if (!IS_INTEGER(AS_TUPLE(seq)->values.values[i])) return krk_runtimeError(vm.exceptions->valueError, "expected int, not %T", AS_TUPLE(seq)->values.values[i]);
}
self->_value.tm_year = AS_INTEGER(AS_TUPLE(seq)->values.values[0]) - 1900;
self->_value.tm_mon = AS_INTEGER(AS_TUPLE(seq)->values.values[1]) - 1;
self->_value.tm_mday = AS_INTEGER(AS_TUPLE(seq)->values.values[2]);
self->_value.tm_hour = AS_INTEGER(AS_TUPLE(seq)->values.values[3]);
self->_value.tm_min = AS_INTEGER(AS_TUPLE(seq)->values.values[4]);
self->_value.tm_sec = AS_INTEGER(AS_TUPLE(seq)->values.values[5]);
self->_value.tm_wday = (AS_INTEGER(AS_TUPLE(seq)->values.values[6])+6)%7;
self->_value.tm_yday = AS_INTEGER(AS_TUPLE(seq)->values.values[7]) - 1;
self->_value.tm_isdst = AS_INTEGER(AS_TUPLE(seq)->values.values[8]);
return NONE_VAL();
}
KRK_Method(struct_time,tm_year) { return INTEGER_VAL(self->_value.tm_year + 1900); } /* struct tm is 1900-indexed, snakes are not */
KRK_Method(struct_time,tm_mon) { return INTEGER_VAL(self->_value.tm_mon + 1); } /* struct tm is 0-indexed, snakes are not */
KRK_Method(struct_time,tm_mday) { return INTEGER_VAL(self->_value.tm_mday); }
KRK_Method(struct_time,tm_hour) { return INTEGER_VAL(self->_value.tm_hour); }
KRK_Method(struct_time,tm_min) { return INTEGER_VAL(self->_value.tm_min); }
KRK_Method(struct_time,tm_sec) { return INTEGER_VAL(self->_value.tm_sec); }
KRK_Method(struct_time,tm_wday) { return INTEGER_VAL((self->_value.tm_wday+1)%7); } /* struct tm has Sunday = 0, but snakes use Monday = 0 */
KRK_Method(struct_time,tm_yday) { return INTEGER_VAL(self->_value.tm_yday+1); } /* struct tm is from 0, but snakes start from 1 */
KRK_Method(struct_time,tm_isdst) { return INTEGER_VAL(self->_value.tm_isdst); }
KRK_Method(struct_time,__repr__) {
return krk_stringFromFormat(
"time.struct_time(tm_year=%d, tm_mon=%d, tm_mday=%d, tm_hour=%d, tm_min=%d, "
"tm_sec=%d, tm_wday=%d, tm_yday=%d, tm_isdst=%d)",
self->_value.tm_year + 1900,
self->_value.tm_mon + 1,
self->_value.tm_mday,
self->_value.tm_hour,
self->_value.tm_min,
self->_value.tm_sec,
(self->_value.tm_wday + 1) % 7,
self->_value.tm_yday + 1,
self->_value.tm_isdst);
}
static time_t time_or_now(int has_arg, long long secs) {
if (!has_arg) {
struct timeval tv;
gettimeofday(&tv,NULL);
return (time_t)tv.tv_sec;
} else {
return (time_t)secs;
}
}
static void tm_or_now(const struct struct_time_obj * t, struct tm * _time) {
if (t) {
memcpy(_time,&t->_value,sizeof(struct tm));
} else {
struct timeval tv;
gettimeofday(&tv,NULL);
time_t time = tv.tv_sec;
localtime_r(&time,_time);
}
}
KRK_Function(localtime) {
int gave_seconds;
long long seconds;
if (!krk_parseArgs("|L?",(const char*[]){"seconds"},&gave_seconds, &seconds)) return NONE_VAL();
time_t time = time_or_now(gave_seconds, seconds);
/* Create a struct_time to store result in */
CURRENT_CTYPE out = (CURRENT_CTYPE)krk_newInstance(struct_time);
krk_push(OBJECT_VAL(out));
if (!localtime_r(&time, &out->_value)) return krk_runtimeError(vm.exceptions->valueError, "?");
return krk_pop();
}
static KrkValue krk_asctime(const struct tm *_time) {
/* asctime is normally locale-aware, but the snake function is not, so we do this manually */
static const char * monNames[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
static const char * dayNames[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
char buf[40] = {0};
/* The normal strftime string for this is %a %b %d %T %Y
* Day Mon DD HH:MM:SS YYYY */
snprintf(buf,39, "%s %s%3d %.2d:%.2d:%.2d %d",
dayNames[_time->tm_wday % 7],
monNames[_time->tm_mon % 12],
_time->tm_mday,
_time->tm_hour,
_time->tm_min,
_time->tm_sec,
_time->tm_year + 1900);
return OBJECT_VAL(krk_copyString(buf,strlen(buf)));
}
KRK_Function(asctime) {
struct struct_time_obj * t = NULL;
if (!krk_parseArgs("|O!",(const char*[]){"t"},struct_time,&t)) return NONE_VAL();
struct tm _time;
tm_or_now(t,&_time);
return krk_asctime(&_time);
}
KRK_Function(ctime) {
int has_arg;
long long secs;
if (!krk_parseArgs("|L?",(const char*[]){"secs"},&has_arg,&secs)) return NONE_VAL();
time_t time = time_or_now(has_arg, secs);
struct tm _time;
if (!localtime_r(&time, &_time)) return krk_runtimeError(vm.exceptions->valueError, "?");
return krk_asctime(&_time);
}
KRK_Function(gmtime) {
int gave_seconds;
long long seconds;
if (!krk_parseArgs("|L?",(const char*[]){"secs"},&gave_seconds, &seconds)) return NONE_VAL();
time_t time = time_or_now(gave_seconds, seconds);
/* Create a struct_time to store result in */
CURRENT_CTYPE out = (CURRENT_CTYPE)krk_newInstance(struct_time);
krk_push(OBJECT_VAL(out));
if (!gmtime_r(&time, &out->_value)) return krk_runtimeError(vm.exceptions->valueError, "?");
return krk_pop();
}
KRK_Function(mktime) {
struct struct_time_obj * t;
if (!krk_parseArgs("O!",(const char*[]){"t"},struct_time,&t)) return NONE_VAL();
struct tm _time;
memcpy(&_time,&t->_value,sizeof(struct tm));
_time.tm_wday = -1;
time_t out = mktime(&_time);
if (out == -1 && _time.tm_wday == -1) return krk_runtimeError(vm.exceptions->valueError, "invalid argument to mktime");
return FLOATING_VAL(out);
}
KRK_Function(strftime) {
const char * format;
struct struct_time_obj * t = NULL;
if (!krk_parseArgs("s|O!",(const char*[]){"format","t"},&format,struct_time,&t)) return NONE_VAL();
struct tm _time;
tm_or_now(t,&_time);
/* strftime wants a buffer size, but we have no way of knowing. Following
* what CPython does, start from 1024 and try doubling until we reach
* the length of our format string * 256, and then give up. */
size_t fmt_len = strlen(format);
size_t size = 1024;
while (1) {
char * buf = malloc(size);
size_t ret = strftime(buf,size,format,&_time);
if (ret || size > fmt_len * 256) {
krk_push(OBJECT_VAL(krk_copyString(buf,ret)));
free(buf);
return krk_pop();
}
size *= 2;
free(buf);
}
}
KRK_Module(time) {
KRK_DOC(module, "@brief Provides timekeeping functions.");
KRK_DOC(BIND_FUNC(module,sleep), "@brief Pause execution of the current thread.\n"
"@arguments secs\n\n"
"Uses the system @c usleep() function to sleep for @p secs seconds, which may be a @ref float or @ref int. "
"The available precision is platform-dependent.");
KRK_DOC(BIND_FUNC(module,time), "@brief Return the elapsed seconds since the system epoch.\n\n"
"Returns a @ref float representation of the number of seconds since the platform's epoch date. "
"On POSIX platforms, this is the number of seconds since 1 January 1970. "
"The precision of the return value is platform-dependent.");
krk_makeClass(module, &struct_time, "struct_time", KRK_BASE_CLASS(object));
struct_time->allocSize = sizeof(struct struct_time_obj);
KRK_DOC(struct_time, "Time value returned by various functions.");
KRK_DOC(BIND_METHOD(struct_time,__init__), "@arguments iterable: tuple\n\n"
"Create a @ref struct_time from a 9-tuple of @ref int values.\n"
"The format of @p iterable is `(tm_year,tm_mon,tm_mday,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)`.");
KRK_DOC(BIND_PROP(struct_time,tm_year), "Calendar year");
KRK_DOC(BIND_PROP(struct_time,tm_mon), "Month, [1, 12]");
KRK_DOC(BIND_PROP(struct_time,tm_mday), "Day of the month, [1, 31]");
KRK_DOC(BIND_PROP(struct_time,tm_hour), "Clock hour, [0, 23]");
KRK_DOC(BIND_PROP(struct_time,tm_min), "Clock minute, [0, 59]");
KRK_DOC(BIND_PROP(struct_time,tm_sec), "Clock seconds, [0, 61] (maybe, due to leap seconds, depends on platform)");
KRK_DOC(BIND_PROP(struct_time,tm_wday), "Day of week, [0, 6], 0 is Monday.");
KRK_DOC(BIND_PROP(struct_time,tm_yday), "Day of year [1, 366]");
KRK_DOC(BIND_PROP(struct_time,tm_isdst), "0, 1, -1 for unknown");
BIND_METHOD(struct_time,__repr__);
krk_finalizeClass(struct_time);
KRK_DOC(BIND_FUNC(module,localtime), "@brief Convert seconds since epoch to local time.\n"
"@arguments seconds=time.time()\n\n"
"If @p seconds is not provided, the current @ref time is used.");
KRK_DOC(BIND_FUNC(module,asctime), "@brief Convert time to string.\n"
"@arguments t=time.localtime()\n\n"
"If @p t is not provided, the current @ref localtime is used.");
KRK_DOC(BIND_FUNC(module,ctime), "@brief Convert seconds since epoch to string.\n"
"@arguments secs=time.time()\n\n"
"If @p secs is not provided, the current @ref time is used.");
KRK_DOC(BIND_FUNC(module,gmtime), "@brief Convert seconds since epoch to UTC time.\n"
"@arguments secs=time.time()\n\n"
"If @p secs is not provided, the current @ref time is used.");
KRK_DOC(BIND_FUNC(module,mktime), "@brief Convert from local time to seconds since epoch.\n"
"@arguments t\n\n"
"For compatibility with @ref time a @ref float is returned.");
KRK_DOC(BIND_FUNC(module,strftime), "@brief Format time string with system function.\n"
"@arguments format,t=time.localtime()\n\n"
"Uses the system `strftime` C function to convert a @ref struct_time to a string.\n"
"If @p t is not provided, the current @ref localtime is used.");
}

View File

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

View File

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

View File

@ -6,22 +6,114 @@
#define CURRENT_NAME self
#define IS_type(o) (1)
#define AS_type(o) (o)
#define CURRENT_CTYPE KrkValue
KRK_Method(type,__init__) {
METHOD_TAKES_EXACTLY(1);
return OBJECT_VAL(krk_getType(argv[1]));
}
#undef IS_type
#undef AS_type
#undef CURRENT_CTYPE
#define IS_type(o) (IS_CLASS(o))
#define AS_type(o) (AS_CLASS(o))
#define CURRENT_CTYPE KrkClass *
static void _callSetName(KrkClass * _class) {
KrkValue setnames = krk_list_of(0,NULL,0);
krk_push(setnames);
extern FUNC_SIG(list,append);
/* The semantics of this require that we first collect all of the relevant items... */
for (size_t i = 0; i < _class->methods.capacity; ++i) {
KrkTableEntry * entry = &_class->methods.entries[i];
if (!IS_KWARGS(entry->key)) {
KrkClass * type = krk_getType(entry->value);
if (type->_set_name) {
FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->key},0);
FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->value},0);
}
}
}
/* Then call __set_name__ on them */
for (size_t i = 0; i < AS_LIST(setnames)->count; i += 2) {
KrkValue name = AS_LIST(setnames)->values[i];
KrkValue value = AS_LIST(setnames)->values[i+1];
KrkClass * type = krk_getType(value);
if (type->_set_name) {
krk_push(value);
krk_push(OBJECT_VAL(_class));
krk_push(name);
krk_callDirect(type->_set_name, 3);
/* If any of these raises an exception, bail; CPython raises
* an outer exception, setting the cause, but I'm being lazy
* at the moment... */
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
break;
}
}
}
/* List used to store name+value pairs */
krk_pop();
}
KRK_StaticMethod(type,__new__) {
KrkClass * metaclass;
KrkString * name;
KrkClass * base;
KrkDict * nspace;
if (!krk_parseArgs("O!O!O!O!~:type",
(const char*[]){"cls","name","base","namespace"},
vm.baseClasses->typeClass, &metaclass,
vm.baseClasses->strClass, &name,
vm.baseClasses->typeClass, &base,
vm.baseClasses->dictClass, &nspace)) {
return NONE_VAL();
}
if (base->obj.flags & KRK_OBJ_FLAGS_NO_INHERIT) {
return krk_runtimeError(vm.exceptions->typeError, "'%S' can not be subclassed", base->name);
}
/* Now make a class */
KrkClass * _class = krk_newClass(name, base);
krk_push(OBJECT_VAL(_class));
_class->_class = metaclass;
/* Now copy the values over */
krk_tableAddAll(&nspace->entries, &_class->methods);
KrkValue tmp;
if (krk_tableGet_fast(&_class->methods, S("__class_getitem__"), &tmp) && IS_CLOSURE(tmp)) {
AS_CLOSURE(tmp)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
}
if (krk_tableGet_fast(&_class->methods, S("__init_subclass__"), &tmp) && IS_CLOSURE(tmp)) {
AS_CLOSURE(tmp)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
}
if (krk_tableGet_fast(&_class->methods, S("__new__"), &tmp) && IS_CLOSURE(tmp)) {
AS_CLOSURE(tmp)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
}
krk_finalizeClass(_class);
_callSetName(_class);
/* Call super().__init_subclass__ */
krk_push(NONE_VAL());
if (!krk_bindMethodSuper(base,S("__init_subclass__"),_class)) {
krk_pop(); /* none */
} else {
if (hasKw) {
krk_push(KWARGS_VAL(KWARGS_DICT));
krk_push(argv[argc]);
krk_push(KWARGS_VAL(1));
krk_callStack(3);
} else {
krk_callStack(0);
}
}
return krk_pop();
}
KRK_Method(type,__base__) {
if (argc > 1) return krk_runtimeError(vm.exceptions->typeError, "__base__ can not be reassigned");
return self->base ? OBJECT_VAL(self->base) : NONE_VAL();
@ -43,15 +135,7 @@ KRK_Method(type,__file__) {
return self->filename ? OBJECT_VAL(self->filename) : NONE_VAL();
}
KRK_Method(type,__doc__) {
if (argc > 1) {
if (!IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]);
self->docstring = AS_STRING(argv[1]);
}
return self->docstring ? OBJECT_VAL(self->docstring) : NONE_VAL();
}
KRK_Method(type,__str__) {
KRK_Method(type,__repr__) {
/* Determine if this class has a module */
KrkValue module = NONE_VAL();
krk_tableGet(&self->methods, OBJECT_VAL(S("__module__")), &module);
@ -90,21 +174,83 @@ KRK_Method(type,__getitem__) {
return krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not subscriptable", "type");
}
KRK_Method(type,__call__) {
if (self == vm.baseClasses->typeClass) {
if (argc == 2) {
return OBJECT_VAL(krk_getType(argv[1]));
}
}
if (!self->_new) {
return krk_runtimeError(vm.exceptions->typeError, "%S() can not be built", self->name);
}
KrkValue result;
if (self->_new->type == KRK_OBJ_NATIVE) {
/* Fast call to native __new__ function. */
result = ((KrkNative*)self->_new)->function(argc,argv,hasKw);
} else {
/* Slow call: Put arguments back on the stack with kwargs call format */
int argCount = argc;
for (int i = 0; i < argc; ++i) {
krk_push(argv[i]);
}
if (hasKw) {
argCount += 3;
krk_push(KWARGS_VAL(KWARGS_DICT));
krk_push(argv[argc]);
krk_push(KWARGS_VAL(1));
}
result = krk_callDirect(self->_new, argCount);
}
/* If an exception happened in __new__, don't try to call __init__ even if the conditions would be right. */
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return NONE_VAL();
if (self->_init != KRK_BASE_CLASS(object)->_init && self->_init != NULL && krk_isInstanceOf(result, self)) {
/* Because we have to swap the class for the instance here, we can't do a fast call even
* if __init__ is a native function, so we're stuck with the slow approach... */
krk_push(result); /* once for safe keeping */
krk_push(result); /* once as an argument */
int argCount = argc;
for (int i = 0; i < argc - 1; ++i) {
krk_push(argv[i+1]);
}
if (hasKw) {
argCount += 3;
krk_push(KWARGS_VAL(KWARGS_DICT));
krk_push(argv[argc]);
krk_push(KWARGS_VAL(1));
}
KrkValue result = krk_callDirect(self->_init, argCount);
if (!IS_NONE(result)) {
fprintf(stderr, "Warning: Non-None result returned from %s.__init__\n",
self->name->chars);
}
return krk_pop();
}
return result;
}
_noexport
void _createAndBind_type(void) {
KrkClass * type = ADD_BASE_CLASS(vm.baseClasses->typeClass, "type", vm.baseClasses->objectClass);
type->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
type->allocSize = sizeof(KrkClass);
BIND_PROP(type,__base__);
BIND_PROP(type,__file__);
BIND_PROP(type,__doc__);
BIND_PROP(type,__name__);
BIND_METHOD(type,__init__);
BIND_METHOD(type,__str__);
BIND_METHOD(type,__repr__);
BIND_METHOD(type,__subclasses__);
BIND_METHOD(type,__getitem__);
krk_defineNative(&type->methods,"__repr__",FUNC_NAME(type,__str__));
BIND_METHOD(type,__call__);
BIND_STATICMETHOD(type,__new__);
krk_finalizeClass(type);
KRK_DOC(type, "Obtain the object representation of the class of an object.");

View File

@ -34,7 +34,7 @@ static int _bytes_callback(void * context, const KrkValue * values, size_t count
return 0;
}
KRK_Method(bytes,__init__) {
KRK_StaticMethod(bytes,__new__) {
if (argc < 2) return OBJECT_VAL(krk_newBytes(0,NULL));
METHOD_TAKES_AT_MOST(1);
@ -275,7 +275,7 @@ KRK_Method(bytesiterator,__init__) {
CHECK_ARG(1,bytes,KrkBytes*,bytes);
self->l = argv[1];
self->i = 0;
return argv[0];
return NONE_VAL();
}
KRK_Method(bytesiterator,__call__) {
@ -304,10 +304,11 @@ KRK_Method(bytearray,__init__) {
self->actual = OBJECT_VAL(krk_newBytes(AS_BYTES(argv[1])->length, AS_BYTES(argv[1])->bytes));
} else if (IS_INTEGER(argv[1])) {
self->actual = OBJECT_VAL(krk_newBytes(AS_INTEGER(argv[1]),NULL));
memset(AS_BYTES(self->actual)->bytes, 0, AS_BYTES(self->actual)->length);
} else {
return krk_runtimeError(vm.exceptions->valueError, "expected bytes");
}
return argv[0];
return NONE_VAL();
}
#undef IS_bytearray
@ -324,15 +325,10 @@ KRK_Method(bytearray,__repr__) {
METHOD_TAKES_NONE();
struct StringBuilder sb = {0};
pushStringBuilderStr(&sb, "bytearray(", 10);
krk_push(self->actual);
KrkValue repred_bytes = krk_callDirect(vm.baseClasses->bytesClass->_reprer, 1);
if (!IS_STRING(repred_bytes)) {
/* Invalid repr of bytes? */
discardStringBuilder(&sb);
if (!krk_pushStringBuilderFormat(&sb, "%R", self->actual)) {
krk_discardStringBuilder(&sb);
return NONE_VAL();
}
pushStringBuilderStr(&sb, AS_STRING(repred_bytes)->chars, AS_STRING(repred_bytes)->length);
pushStringBuilder(&sb,')');
return finishStringBuilder(&sb);
}
@ -420,7 +416,8 @@ _noexport
void _createAndBind_bytesClass(void) {
KrkClass * bytes = ADD_BASE_CLASS(vm.baseClasses->bytesClass, "bytes", vm.baseClasses->objectClass);
bytes->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
KRK_DOC(BIND_METHOD(bytes,__init__),
bytes->allocSize = 0;
KRK_DOC(BIND_STATICMETHOD(bytes,__new__),
"@brief An array of bytes.\n"
"@arguments iter=None\n\n"
"Creates a new @ref bytes object. If @p iter is provided, it should be a @ref tuple or @ref list "
@ -435,7 +432,6 @@ void _createAndBind_bytesClass(void) {
BIND_METHOD(bytes,__hash__);
BIND_METHOD(bytes,decode);
BIND_METHOD(bytes,join);
krk_defineNative(&bytes->methods,"__str__",FUNC_NAME(bytes,__repr__)); /* alias */
krk_finalizeClass(bytes);
KrkClass * bytesiterator = ADD_BASE_CLASS(vm.baseClasses->bytesiteratorClass, "bytesiterator", vm.baseClasses->objectClass);
@ -460,6 +456,5 @@ void _createAndBind_bytesClass(void) {
BIND_METHOD(bytearray,__eq__);
BIND_METHOD(bytearray,__iter__);
BIND_METHOD(bytearray,decode);
krk_defineNative(&bytearray->methods,"__str__",FUNC_NAME(bytearray,__repr__)); /* alias */
krk_finalizeClass(bytearray);
}

View File

@ -4,6 +4,14 @@
#include <kuroko/memory.h>
#include <kuroko/util.h>
#if defined(__TINYC__) || (defined(_MSC_VER) && !defined(__clang__))
static int __builtin_clz(unsigned int x) {
int i = 31;
while (!(x & (1 << i)) && i >= 0) i--;
return 31-i;
}
#endif
/**
* Exposed method called to produce dictionaries from `{expr: expr, ...}` sequences in managed code.
* Expects arguments as `key,value,key,value`...
@ -13,9 +21,15 @@ KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw) {
KrkInstance * outDict = krk_newInstance(vm.baseClasses->dictClass);
krk_push(OBJECT_VAL(outDict));
krk_initTable(&((KrkDict*)outDict)->entries);
krk_tableAdjustCapacity(&((KrkDict*)outDict)->entries, argc);
for (int ind = 0; ind < argc; ind += 2) {
krk_tableSet(&((KrkDict*)outDict)->entries, argv[ind], argv[ind+1]);
if (argc) {
size_t capacity = argc;
size_t powerOfTwoCapacity = __builtin_clz(1) - __builtin_clz(capacity);
if ((1UL << powerOfTwoCapacity) != capacity) powerOfTwoCapacity++;
capacity = (1UL << powerOfTwoCapacity);
krk_tableAdjustCapacity(&((KrkDict*)outDict)->entries, capacity);
for (int ind = 0; ind < argc; ind += 2) {
krk_tableSet(&((KrkDict*)outDict)->entries, argv[ind], argv[ind+1]);
}
}
return krk_pop();
}
@ -87,7 +101,8 @@ KRK_Method(dict,__init__) {
if (hasKw) {
krk_tableAddAll(AS_DICT(argv[argc]), &self->entries);
}
return argv[0];
return NONE_VAL();
}
KRK_Method(dict,__eq__) {
@ -152,8 +167,8 @@ KRK_Method(dict,__len__) {
KRK_Method(dict,__contains__) {
METHOD_TAKES_EXACTLY(1);
KrkValue _unused;
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &_unused));
KrkValue v;
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &v));
}
KRK_Method(dict,capacity) {
@ -173,35 +188,21 @@ KRK_Method(dict,__repr__) {
for (size_t i = 0; i < len; ++i) {
KrkTableEntry * entry = &self->entries.entries[i];
if (IS_KWARGS(entry->key)) continue;
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
}
if (c) pushStringBuilderStr(&sb, ", ", 2);
c++;
{
KrkClass * type = krk_getType(entry->key);
krk_push(entry->key);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
}
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
pushStringBuilderStr(&sb, ": ", 2);
{
KrkClass * type = krk_getType(entry->value);
krk_push(entry->value);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
}
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->value)) goto _error;
}
pushStringBuilder(&sb,'}');
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
return finishStringBuilder(&sb);
_error:
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
krk_discardStringBuilder(&sb);
return NONE_VAL();
}
KRK_Method(dict,copy) {
@ -316,7 +317,7 @@ KRK_Method(dictitems,__init__) {
CHECK_ARG(1,dict,KrkDict*,source);
self->dict = argv[1];
self->i = 0;
return argv[0];
return NONE_VAL();
}
KRK_Method(dictitems,__iter__) {
@ -327,7 +328,7 @@ KRK_Method(dictitems,__iter__) {
KRK_Method(dictitems,__call__) {
do {
if (self->i >= AS_DICT(self->dict)->capacity) return argv[0];
if (self->i >= AS_DICT(self->dict)->used) return argv[0];
if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
KrkTuple * outValue = krk_newTuple(2);
krk_push(OBJECT_VAL(outValue));
@ -349,43 +350,27 @@ KRK_Method(dictitems,__repr__) {
pushStringBuilderStr(&sb,"dictitems([",11);
size_t c = 0;
size_t len = AS_DICT(self->dict)->capacity;
size_t len = AS_DICT(self->dict)->used;
for (size_t i = 0; i < len; ++i) {
KrkTableEntry * entry = &AS_DICT(self->dict)->entries[i];
if (IS_KWARGS(entry->key)) continue;
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
}
if (c) pushStringBuilderStr(&sb, ", ", 2);
c++;
pushStringBuilder(&sb,'(');
{
KrkClass * type = krk_getType(entry->key);
krk_push(entry->key);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
}
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
pushStringBuilderStr(&sb, ", ", 2);
{
KrkClass * type = krk_getType(entry->value);
krk_push(entry->value);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
}
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->value)) goto _error;
pushStringBuilder(&sb,')');
}
pushStringBuilderStr(&sb,"])",2);
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
return finishStringBuilder(&sb);
_error:
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
krk_discardStringBuilder(&sb);
return NONE_VAL();
}
#undef CURRENT_CTYPE
@ -400,7 +385,7 @@ KRK_Method(dictkeys,__init__) {
CHECK_ARG(1,dict,KrkDict*,source);
self->dict = argv[1];
self->i = 0;
return argv[0];
return NONE_VAL();
}
KRK_Method(dictkeys,__iter__) {
@ -412,7 +397,7 @@ KRK_Method(dictkeys,__iter__) {
KRK_Method(dictkeys,__call__) {
METHOD_TAKES_NONE();
do {
if (self->i >= AS_DICT(self->dict)->capacity) return argv[0];
if (self->i >= AS_DICT(self->dict)->used) return argv[0];
if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
krk_push(AS_DICT(self->dict)->entries[self->i].key);
self->i++;
@ -430,28 +415,23 @@ KRK_Method(dictkeys,__repr__) {
pushStringBuilderStr(&sb,"dictkeys([",10);
size_t c = 0;
size_t len = AS_DICT(self->dict)->capacity;
size_t len = AS_DICT(self->dict)->used;
for (size_t i = 0; i < len; ++i) {
KrkTableEntry * entry = &AS_DICT(self->dict)->entries[i];
if (IS_KWARGS(entry->key)) continue;
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
}
if (c) pushStringBuilderStr(&sb, ", ", 2);
c++;
{
KrkClass * type = krk_getType(entry->key);
krk_push(entry->key);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
}
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
}
pushStringBuilderStr(&sb,"])",2);
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
return finishStringBuilder(&sb);
_error:
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
krk_discardStringBuilder(&sb);
return NONE_VAL();
}
#undef CURRENT_CTYPE
@ -466,7 +446,7 @@ KRK_Method(dictvalues,__init__) {
CHECK_ARG(1,dict,KrkDict*,source);
self->dict = argv[1];
self->i = 0;
return argv[0];
return NONE_VAL();
}
KRK_Method(dictvalues,__iter__) {
@ -478,7 +458,7 @@ KRK_Method(dictvalues,__iter__) {
KRK_Method(dictvalues,__call__) {
METHOD_TAKES_NONE();
do {
if (self->i >= AS_DICT(self->dict)->capacity) return argv[0];
if (self->i >= AS_DICT(self->dict)->used) return argv[0];
if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
krk_push(AS_DICT(self->dict)->entries[self->i].value);
self->i++;
@ -496,28 +476,23 @@ KRK_Method(dictvalues,__repr__) {
pushStringBuilderStr(&sb,"dictvalues([",12);
size_t c = 0;
size_t len = AS_DICT(self->dict)->capacity;
size_t len = AS_DICT(self->dict)->used;
for (size_t i = 0; i < len; ++i) {
KrkTableEntry * entry = &AS_DICT(self->dict)->entries[i];
if (IS_KWARGS(entry->key)) continue;
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
}
if (c) pushStringBuilderStr(&sb, ", ", 2);
c++;
{
KrkClass * type = krk_getType(entry->value);
krk_push(entry->value);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
}
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->value)) goto _error;
}
pushStringBuilderStr(&sb,"])",2);
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
return finishStringBuilder(&sb);
_error:
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
krk_discardStringBuilder(&sb);
return NONE_VAL();
}
_noexport
@ -546,7 +521,6 @@ void _createAndBind_dictClass(void) {
BIND_METHOD(dict,setdefault);
BIND_METHOD(dict,update);
krk_defineNative(&dict->methods, "__iter__", FUNC_NAME(dict,keys));
krk_defineNative(&dict->methods, "__str__", FUNC_NAME(dict,__repr__));
krk_defineNative(&dict->methods, "__class_getitem__", krk_GenericAlias)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
krk_attachNamedValue(&dict->methods, "__hash__", NONE_VAL());
krk_finalizeClass(dict);

View File

@ -46,8 +46,7 @@ static KrkTuple * functionArgs(KrkCodeObject * _self) {
#define CURRENT_NAME self
#define CURRENT_CTYPE KrkValue
FUNC_SIG(function,__init__) {
static __attribute__ ((unused)) const char* _method_name = "__init__";
KRK_StaticMethod(function,__new__) {
METHOD_TAKES_EXACTLY(3);
CHECK_ARG(1,codeobject,KrkCodeObject*,code);
@ -138,7 +137,7 @@ KRK_Method(function,_ip_to_line) {
return INTEGER_VAL(line);
}
KRK_Method(function,__str__) {
KRK_Method(function,__repr__) {
METHOD_TAKES_NONE();
/* Do we have a qualified name? */
@ -188,10 +187,26 @@ KRK_Method(function,__code__) {
return OBJECT_VAL(AS_CLOSURE(self)->function);
}
KRK_Method(function,__closure__) {
ATTRIBUTE_NOT_ASSIGNABLE();
if (!IS_CLOSURE(self)) {
return OBJECT_VAL(krk_newTuple(0));
}
size_t cnt = AS_CLOSURE(self)->upvalueCount;
KrkTuple * out = krk_newTuple(cnt);
krk_push(OBJECT_VAL(out));
for (size_t i = 0; i < cnt; ++i) {
out->values.values[out->values.count++] = OBJECT_VAL(AS_CLOSURE(self)->upvalues[i]);
}
return krk_pop();
}
#undef CURRENT_CTYPE
#define CURRENT_CTYPE KrkCodeObject*
FUNC_SIG(codeobject,__init__) {
KRK_StaticMethod(codeobject,__new__) {
return krk_runtimeError(vm.exceptions->typeError, "codeobject object is not instantiable");
}
@ -200,7 +215,7 @@ KRK_Method(codeobject,__name__) {
return self->name ? OBJECT_VAL(self->name) : OBJECT_VAL(S(""));
}
KRK_Method(codeobject,__str__) {
KRK_Method(codeobject,__repr__) {
METHOD_TAKES_NONE();
KrkValue s = FUNC_NAME(codeobject,__name__)(1,argv,0);
if (!IS_STRING(s)) return NONE_VAL();
@ -288,15 +303,18 @@ KRK_Method(codeobject,__args__) {
return OBJECT_VAL(tuple);
}
KRK_Method(codeobject,__file__) {
ATTRIBUTE_NOT_ASSIGNABLE();
return self->chunk.filename ? OBJECT_VAL(self->chunk.filename) : OBJECT_VAL(S(""));
}
#undef CURRENT_CTYPE
#define CURRENT_CTYPE KrkBoundMethod*
/* __init__ here will be called with a dummy instance as argv[0]; avoid
* complications with method argument checking by not using KRK_METHOD. */
FUNC_SIG(method,__init__) {
static __attribute__ ((unused)) const char* _method_name = "__init__";
METHOD_TAKES_EXACTLY(2);
KRK_StaticMethod(method,__new__) {
FUNCTION_TAKES_EXACTLY(3);
if (!IS_OBJECT(argv[1])) return krk_runtimeError(vm.exceptions->typeError, "first argument must be a heap object");
return OBJECT_VAL(krk_newBoundMethod(argv[2],AS_OBJECT(argv[1])));
}
@ -316,7 +334,7 @@ KRK_Method(method,_ip_to_line) {
return IS_function(OBJECT_VAL(self->method)) ? FUNC_NAME(function,_ip_to_line)(2,(KrkValue[]){OBJECT_VAL(self->method),argv[1]},0) : OBJECT_VAL(S("?"));
}
KRK_Method(method,__str__) {
KRK_Method(method,__repr__) {
METHOD_TAKES_NONE();
KrkValue s = FUNC_NAME(method,__qualname__)(1,argv,0);
if (!IS_STRING(s)) s = FUNC_NAME(method,__name__)(1,argv,0);
@ -365,31 +383,32 @@ KRK_Method(method,__func__) {
KRK_Method(method,__self__) {
ATTRIBUTE_NOT_ASSIGNABLE();
return OBJECT_VAL(self->receiver);
return self->receiver;
}
KRK_Function(staticmethod) {
FUNCTION_TAKES_EXACTLY(1);
CHECK_ARG(0,CLOSURE,KrkClosure*,method);
method->obj.flags &= ~(KRK_OBJ_FLAGS_FUNCTION_MASK);
method->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
return argv[0];
KrkObj* method;
if (!krk_parseArgs("O!", (const char*[]){"method"}, KRK_BASE_CLASS(function), &method)) return NONE_VAL();
method->flags &= ~(KRK_OBJ_FLAGS_FUNCTION_MASK);
method->flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD;
return OBJECT_VAL(method);
}
KRK_Function(classmethod) {
FUNCTION_TAKES_EXACTLY(1);
CHECK_ARG(0,CLOSURE,KrkClosure*,method);
method->obj.flags &= ~(KRK_OBJ_FLAGS_FUNCTION_MASK);
method->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
return argv[0];
KrkObj* method;
if (!krk_parseArgs("O!", (const char*[]){"method"}, KRK_BASE_CLASS(function), &method)) return NONE_VAL();
method->flags &= ~(KRK_OBJ_FLAGS_FUNCTION_MASK);
method->flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
return OBJECT_VAL(method);
}
_noexport
void _createAndBind_functionClass(void) {
KrkClass * codeobject = ADD_BASE_CLASS(vm.baseClasses->codeobjectClass, "codeobject", vm.baseClasses->objectClass);
codeobject->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_METHOD(codeobject,__init__);
BIND_METHOD(codeobject,__str__);
codeobject->allocSize = 0;
BIND_STATICMETHOD(codeobject,__new__);
BIND_METHOD(codeobject,__repr__);
BIND_METHOD(codeobject,_ip_to_line);
BIND_PROP(codeobject,__constants__);
BIND_PROP(codeobject,__name__);
@ -400,13 +419,14 @@ void _createAndBind_functionClass(void) {
BIND_PROP(codeobject,co_posonlyargcount);
BIND_PROP(codeobject,__locals__);
BIND_PROP(codeobject,__args__);
krk_defineNative(&codeobject->methods, "__repr__", FUNC_NAME(codeobject,__str__));
BIND_PROP(codeobject,__file__);
krk_finalizeClass(codeobject);
KrkClass * function = ADD_BASE_CLASS(vm.baseClasses->functionClass, "function", vm.baseClasses->objectClass);
function->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_METHOD(function,__init__);
BIND_METHOD(function,__str__);
function->allocSize = 0;
BIND_STATICMETHOD(function,__new__);
BIND_METHOD(function,__repr__);
BIND_METHOD(function,_ip_to_line);
BIND_PROP(function,__doc__);
BIND_PROP(function,__name__);
@ -416,15 +436,16 @@ void _createAndBind_functionClass(void) {
BIND_PROP(function,__annotations__);
BIND_PROP(function,__code__);
BIND_PROP(function,__globals__);
krk_defineNative(&function->methods, "__repr__", FUNC_NAME(function,__str__));
BIND_PROP(function,__closure__);
krk_defineNative(&function->methods, "__class_getitem__", krk_GenericAlias)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
krk_finalizeClass(function);
KrkClass * method = ADD_BASE_CLASS(vm.baseClasses->methodClass, "method", vm.baseClasses->objectClass);
method->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_METHOD(method,__str__);
method->allocSize = 0;
BIND_STATICMETHOD(method,__new__);
BIND_METHOD(method,__repr__);
BIND_METHOD(method,_ip_to_line);
BIND_METHOD(method,__init__);
BIND_PROP(method,__doc__);
BIND_PROP(method,__name__);
BIND_PROP(method,__qualname__);
@ -434,7 +455,6 @@ void _createAndBind_functionClass(void) {
BIND_PROP(method,__self__);
BIND_PROP(method,__func__);
BIND_PROP(method,__code__);
krk_defineNative(&method->methods, "__repr__", FUNC_NAME(method,__str__));
krk_finalizeClass(method);
BUILTIN_FUNCTION("staticmethod", FUNC_NAME(krk,staticmethod), "A static method does not take an implicit self or cls argument.");

View File

@ -272,6 +272,5 @@ void _createAndBind_generatorClass(void) {
BIND_METHOD(generator,__finish__);
BIND_METHOD(generator,send);
BIND_PROP(generator,gi_running);
krk_defineNative(&generator->methods, "__str__", FUNC_NAME(generator,__repr__));
krk_finalizeClass(generator);
}

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 = GROW_ARRAY(KrkValue, AS_LIST(outList)->values, 0, argc);
AS_LIST(outList)->values = KRK_GROW_ARRAY(KrkValue, AS_LIST(outList)->values, 0, argc);
memcpy(AS_LIST(outList)->values, argv, sizeof(KrkValue) * argc);
AS_LIST(outList)->count = argc;
}
@ -138,15 +138,7 @@ KRK_Method(list,__repr__) {
pushStringBuilder(&sb, '[');
pthread_rwlock_rdlock(&self->rwlock);
for (size_t i = 0; i < self->values.count; ++i) {
/* repr(self[i]) */
KrkClass * type = krk_getType(self->values.values[i]);
krk_push(self->values.values[i]);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
}
if (!krk_pushStringBuilderFormat(&sb,"%R",self->values.values[i])) goto _error;
if (i + 1 < self->values.count) {
pushStringBuilderStr(&sb, ", ", 2);
}
@ -156,14 +148,20 @@ KRK_Method(list,__repr__) {
pushStringBuilder(&sb,']');
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
return finishStringBuilder(&sb);
_error:
krk_discardStringBuilder(&sb);
pthread_rwlock_unlock(&self->rwlock);
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
return NONE_VAL();
}
static int _list_extend_callback(void * context, const KrkValue * values, size_t count) {
KrkValueArray * positionals = context;
if (positionals->count + count > positionals->capacity) {
size_t old = positionals->capacity;
positionals->capacity = (count == 1) ? GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
positionals->capacity = (count == 1) ? KRK_GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = KRK_GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
}
for (size_t i = 0; i < count; ++i) {
@ -195,7 +193,7 @@ KRK_Method(list,__init__) {
if (argc == 2) {
_list_extend(2,(KrkValue[]){argv[0],argv[1]},0);
}
return argv[0];
return NONE_VAL();
}
KRK_Method(list,__mul__) {
@ -306,7 +304,7 @@ KRK_Method(list,__delitem__) {
METHOD_TAKES_EXACTLY(1);
if (IS_INTEGER(argv[1])) {
FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0],INTEGER_VAL(argv[1])},0);
FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0],argv[1]},0);
} else if (IS_slice(argv[1])) {
KRK_SLICER(argv[1],self->values.count) {
return NONE_VAL();
@ -416,36 +414,338 @@ KRK_Method(list,copy) {
return result;
}
/** @brief In-place reverse a value array. */
static void reverse_values(KrkValue * values, size_t n) {
KrkValue * end = values + n - 1;
while (values < end) {
krk_currentThread.scratchSpace[0] = *values;
*values = *end;
*end = krk_currentThread.scratchSpace[0];
values++;
end--;
}
krk_currentThread.scratchSpace[0] = NONE_VAL();
}
KRK_Method(list,reverse) {
METHOD_TAKES_NONE();
pthread_rwlock_wrlock(&self->rwlock);
for (size_t i = 0; i < (self->values.count) / 2; i++) {
KrkValue tmp = self->values.values[i];
self->values.values[i] = self->values.values[self->values.count-i-1];
self->values.values[self->values.count-i-1] = tmp;
}
if (self->values.count > 1) reverse_values(self->values.values, self->values.count);
pthread_rwlock_unlock(&self->rwlock);
return NONE_VAL();
}
static int _list_sorter(const void * _a, const void * _b) {
KrkValue a = *(KrkValue*)_a;
KrkValue b = *(KrkValue*)_b;
struct SortSlice {
KrkValue * keys;
KrkValue * values;
};
/* Avoid actually calling the sort function if there's an active exception */
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return -1;
KrkValue ltComp = krk_operator_lt(a,b);
if (IS_NONE(ltComp) || (IS_BOOLEAN(ltComp) && AS_BOOLEAN(ltComp))) return -1;
KrkValue gtComp = krk_operator_gt(a,b);
if (IS_NONE(gtComp) || (IS_BOOLEAN(gtComp) && AS_BOOLEAN(gtComp))) return 1;
return 0;
struct SliceAndPower {
struct SortSlice begin;
size_t power;
};
struct Run {
struct SortSlice start;
struct SortSlice end;
size_t power;
};
/** @brief s++ */
static inline void slice_advance(struct SortSlice * slice) {
slice->keys++;
if (slice->values) slice->values++;
}
/** @brief s-- */
static inline void slice_decrement(struct SortSlice * slice) {
slice->keys--;
if (slice->values) slice->values--;
}
/* @brief s + 1 */
static struct SortSlice slice_next(struct SortSlice slice) {
return (struct SortSlice){slice.keys + 1, slice.values ? slice.values + 1 : NULL};
}
/** @brief s + n */
static struct SortSlice slice_plus(struct SortSlice slice, ssize_t n) {
return (struct SortSlice){slice.keys + n, slice.values ? slice.values + n : NULL};
}
/** @brief Copy start-end to buffer */
static void copy_slice(struct SortSlice start, struct SortSlice end, struct SortSlice buffer) {
while (start.keys != end.keys) {
*buffer.keys = *start.keys;
if (buffer.values) *buffer.values = *start.values;
slice_advance(&start);
slice_advance(&buffer);
}
}
/** @brief Very strictly a < b */
static int _list_sorter(KrkValue a, KrkValue b) {
KrkValue comp = krk_operator_lt(a,b);
return (IS_NONE(comp) || (IS_BOOLEAN(comp) && AS_BOOLEAN(comp)));
}
/** @brief While next is strictly < current, advance current */
static struct SortSlice powersort_strictlyDecreasingPrefix(struct SortSlice begin, struct SortSlice end) {
while (begin.keys + 1 < end.keys && _list_sorter(*(begin.keys + 1), *begin.keys)) slice_advance(&begin);
return slice_next(begin);
}
/** @brief While next is greater than or equal to current, advance current */
static struct SortSlice powersort_weaklyIncreasingPrefix(struct SortSlice begin, struct SortSlice end) {
while (begin.keys + 1 < end.keys && !_list_sorter(*(begin.keys + 1), *begin.keys)) slice_advance(&begin);
return slice_next(begin);
}
/**
* @brief Extend a run to the right
*
* Returns a slice pointing at the end of the run after extended it to the right.
* The resulting run consists of strictly ordered (a <= b, b > a) entries. We also
* handle reverse runs by reversing them in-place.
*
* @param begin Start of run
* @param end End of available input to scan; always end of list.
* @returns Slice pointing to end of run
*/
static struct SortSlice powersort_extend_and_reverse_right(struct SortSlice begin, struct SortSlice end) {
struct SortSlice j = begin;
if (j.keys == end.keys) return j;
if (j.keys + 1 == end.keys) return slice_next(j);
if (_list_sorter(*slice_next(j).keys, *j.keys)) {
/* If next is strictly less than current, begin a reversed chain; we already know
* we can advance by one, so do that before continuing to save a comparison. */
j = powersort_strictlyDecreasingPrefix(slice_next(begin), end);
reverse_values(begin.keys, j.keys - begin.keys);
if (begin.values) reverse_values(begin.values, j.values - begin.values);
} else {
/* Weakly increasing means j+1 >= j; continue with that chain*/
j = powersort_weaklyIncreasingPrefix(slice_next(begin), end);
}
return j;
}
/**
* @brief Calculate power.
*
* I'll be honest here, I don't really know what this does; it's from the reference impl.
* and described in the paper.
*/
static size_t powersort_power(size_t begin, size_t end, size_t beginA, size_t beginB, size_t endB) {
size_t n = end - begin;
unsigned long l = beginA - begin + beginB - begin;
unsigned long r = beginB - begin + endB - begin;
size_t common = 0;
int digitA = l >= n;
int digitB = r >= n;
while (digitA == digitB) {
common++;
if (digitA) {
l -= n;
r -= n;
}
l <<= 1;
r <<= 1;
digitA = l >= n;
digitB = r >= n;
}
return common + 1;
}
/**
* @brief Merge neighboring runs.
*
* Merges the neighboring, sorted runs [left, mid) and [mid, right) using the provided
* buffer space. Specifically, the smaller of the two runs is copied to the buffer, and
* then merging occurs in-place.
*
* @param left Start of the first run
* @param mid End of first run, start of second run
* @param right End of second run
* @param buffer Scratch space
*/
static void powersort_merge(struct SortSlice left, struct SortSlice mid, struct SortSlice right, struct SortSlice buffer) {
size_t n1 = mid.keys - left.keys;
size_t n2 = right.keys - mid.keys;
if (n1 <= n2) {
copy_slice(left, mid, buffer);
struct SortSlice c1 = buffer, e1 = slice_plus(buffer, n1);
struct SortSlice c2 = mid, e2 = right, o = left;
while (c1.keys < e1.keys && c2.keys < e2.keys) {
if (!_list_sorter(*c2.keys, *c1.keys)) {
*o.keys = *c1.keys;
if (o.values) *o.values = *c1.values;
slice_advance(&c1);
} else {
*o.keys = *c2.keys;
if (o.values) *o.values = *c2.values;
slice_advance(&c2);
}
slice_advance(&o);
}
while (c1.keys < e1.keys) {
*o.keys = *c1.keys;
if (o.values) *o.values = *c1.values;
slice_advance(&c1);
slice_advance(&o);
}
} else {
copy_slice(mid, right, buffer);
struct SortSlice c1 = slice_plus(mid, -1), s1 = left, o = slice_plus(right, -1);
struct SortSlice c2 = slice_plus(buffer, n2 - 1), s2 = buffer;
while (c1.keys >= s1.keys && c2.keys >= s2.keys) {
if (!_list_sorter(*c2.keys, *c1.keys)) {
*o.keys = *c2.keys;
if (o.values) *o.values = *c2.values;
slice_decrement(&c2);
} else {
*o.keys = *c1.keys;
if (o.values) *o.values = *c1.values;
slice_decrement(&c1);
}
slice_decrement(&o);
}
while (c2.keys >= s2.keys) {
*o.keys = *c2.keys;
if (o.values) *o.values = *c2.values;
slice_decrement(&c2);
slice_decrement(&o);
}
}
}
/**
* @brief Powersort - merge-sort sorted runs
*
* This is an implementation of Munro-Wild Powersort from the paper at:
* @ref https://www.wild-inter.net/publications/html/munro-wild-2018.pdf.html
*
* The reference implementation was also a helpful thing to study, and much
* of the iteration and merging is based on its use of C++ iterators:
* @ref https://github.com/sebawild/powersort
*
* There's no fancy extensions or improvements here, just the plain approach
* set out in the paper, which is probably good enough for us? That means no
* extending short runs to a minimum run length, no fancy node power calcs,
* just a short bit of extending and merging.
*
* If the key function raises an exception, no sorting will be attempted
* and the exception from the key function will be raised immediately.
*
* If the values to be sorted can not compare with __lt__, an exception
* should be thrown eventually, but the entire list may still be scanned
* and the resulting state is undefined.
*
* @param list List to sort in-place.
* @param key Key function, or None to sort values directly.
* @param reverse Sort direction, 0 for normal (a[0] <= b[0], etc.), 1 for reversed.
*/
static void powersort(KrkList * list, KrkValue key, int reverse) {
size_t n = list->values.count;
struct SortSlice slice = {list->values.values, NULL};
/* If there is a key function, create a separate array to store
* the resulting key values; shove it in a tuple so we can keep
* those key values from being garbage collected. */
if (!IS_NONE(key)) {
KrkTuple * _keys = krk_newTuple(n);
krk_push(OBJECT_VAL(_keys));
for (size_t i = 0; i < n; ++i) {
krk_push(key);
krk_push(list->values.values[i]);
_keys->values.values[i] = krk_callStack(1);
_keys->values.count++;
/* If the key function threw an exception, bail early. */
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _end_sort;
}
/* values are secondary, keys are what actually gets sorted */
slice.values = slice.keys;
slice.keys = _keys->values.values;
}
/* We handle reverse sort by reversing, sorting normally, and then reversing again */
if (reverse) {
reverse_values(slice.keys, n);
if (slice.values) reverse_values(slice.values, n);
}
/* Supposedly the absolute maximum for this is strictly less than the number of bits
* we can fit in a size_t, so 64 ought to cover us until someone tries porting Kuroko
* to one of the 128-bit architectures, but even then I don't think we can handle
* holding that many values in a list to begin with.
*
* stack[0] should always be empty. */
struct SliceAndPower stack[64] = {0};
int top = 0;
/* Buffer space for the merges. We shouldn't need anywhere close to this much space,
* but best to be safe, and we're already allocating a bunch of space for key tuples */
KrkTuple * bufferSpace = krk_newTuple(slice.values ? (n * 2) : n);
krk_push(OBJECT_VAL(bufferSpace));
for (size_t i = 0; i < bufferSpace->values.capacity; ++i) bufferSpace->values.values[bufferSpace->values.count++] = NONE_VAL();
struct SortSlice buffer = {&bufferSpace->values.values[0], slice.values ? &bufferSpace->values.values[n] : NULL};
/* This just take the role of the C++ iterators in the reference implementaiton */
struct SortSlice begin = {slice.keys, slice.values};
struct SortSlice end = {slice.keys + n, slice.values ? slice.values + n : NULL};
/* Our first run starts from the left and extends as far as it can. */
struct Run a = {begin, powersort_extend_and_reverse_right(begin,end), 0};
while (a.end.keys < end.keys) {
/* Our next run is whatever is after that, assuming the initial run isn't the whole list. */
struct Run b = {a.end, powersort_extend_and_reverse_right(a.end, end), 0};
/* I don't really understand the power part of powersort, but whatever. */
a.power = powersort_power(0, n, a.start.keys - begin.keys, b.start.keys - begin.keys, b.end.keys - begin.keys);
/* While the stack has things with higher power, merge them into a */
while (stack[top].power > a.power) {
struct SliceAndPower top_run = stack[top--];
powersort_merge(top_run.begin, a.start, a.end, buffer);
a.start = top_run.begin;
}
/* Put a on top of the stack, and then replace a with b */
stack[++top] = (struct SliceAndPower){a.start, a.power};
a = (struct Run){b.start, b.end, 0};
}
/* While there are things in the stack (excluding the empty 0 slot), merge them into the last a */
while (top > 0) {
struct SliceAndPower top_run = stack[top--];
powersort_merge(top_run.begin, a.start, end, buffer);
a.start = top_run.begin;
}
krk_pop(); /* tuple with buffer space */
_end_sort:
if (!IS_NONE(key)) krk_pop(); /* keys tuple */
/* If we reversed at the start, reverse again now as the list is forward-sorted */
if (reverse) reverse_values(list->values.values, n);
}
KRK_Method(list,sort) {
METHOD_TAKES_NONE();
KrkValue key = NONE_VAL();
int reverse = 0;
if (!krk_parseArgs(".|$Vp", (const char*[]){"key","reverse"}, &key, &reverse)) return NONE_VAL();
if (self->values.count < 2) return NONE_VAL();
pthread_rwlock_wrlock(&self->rwlock);
qsort(self->values.values, self->values.count, sizeof(KrkValue), _list_sorter);
powersort(self, key, reverse);
pthread_rwlock_unlock(&self->rwlock);
return NONE_VAL();
@ -517,11 +817,11 @@ KRK_Method(listiterator,__init__) {
CHECK_ARG(1,list,KrkList*,list);
self->l = argv[1];
self->i = 0;
return argv[0];
return NONE_VAL();
}
FUNC_SIG(listiterator,__call__) {
static __attribute__ ((unused)) const char* _method_name = "__call__";
static _unused const char* _method_name = "__call__";
if (unlikely((argc != 1))) goto _bad;
if (unlikely(!IS_OBJECT(argv[0]))) goto _bad;
if (unlikely(AS_INSTANCE(argv[0])->_class != vm.baseClasses->listiteratorClass)) goto _bad;
@ -544,18 +844,18 @@ _bad:
goto _maybeGood;
}
static KrkValue _sorted(int argc, const KrkValue argv[], int hasKw) {
if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError,"%s() takes %s %d argument%s (%d given)","sorted","exactly",1,"",argc);
KRK_Function(sorted) {
if (argc < 1) return krk_runtimeError(vm.exceptions->argumentError,"%s() takes %s %d argument%s (%d given)","sorted","at least",1,"",argc);
KrkValue listOut = krk_list_of(0,NULL,0);
krk_push(listOut);
FUNC_NAME(list,extend)(2,(KrkValue[]){listOut,argv[0]},0);
if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL();
FUNC_NAME(list,sort)(1,&listOut,0);
FUNC_NAME(list,sort)(1,(KrkValue[]){listOut,hasKw ? argv[1] : NONE_VAL(), hasKw ? argv[2] : NONE_VAL()},hasKw);
if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL();
return krk_pop();
}
static KrkValue _reversed(int argc, const KrkValue argv[], int hasKw) {
KRK_Function(reversed) {
/* FIXME The Python reversed() function produces an iterator and only works for things with indexing or a __reversed__ method;
* Building a list and reversing it like we do here is not correct! */
if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError,"%s() takes %s %d argument%s (%d given)","reversed","exactly",1,"",argc);
@ -640,17 +940,16 @@ void _createAndBind_listClass(void) {
"@brief Sort the contents of a list.\n\n"
"Performs an in-place sort of the elements in the list, returning @c None as a gentle reminder "
"that the sort is in-place. If a sorted copy is desired, use @ref sorted instead.");
krk_defineNative(&list->methods, "__str__", FUNC_NAME(list,__repr__));
krk_defineNative(&list->methods, "__class_getitem__", krk_GenericAlias)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD;
krk_attachNamedValue(&list->methods, "__hash__", NONE_VAL());
krk_finalizeClass(list);
KRK_DOC(list, "Mutable sequence of arbitrary values.");
BUILTIN_FUNCTION("sorted", _sorted,
BUILTIN_FUNCTION("sorted", FUNC_NAME(krk,sorted),
"@brief Return a sorted representation of an iterable.\n"
"@arguments iterable\n\n"
"Creates a new, sorted list from the elements of @p iterable.");
BUILTIN_FUNCTION("reversed", _reversed,
BUILTIN_FUNCTION("reversed", FUNC_NAME(krk,reversed),
"@brief Return a reversed representation of an iterable.\n"
"@arguments iterable\n\n"
"Creates a new, reversed list from the elements of @p iterable.");

File diff suppressed because it is too large Load Diff

View File

@ -16,39 +16,69 @@
extern KrkValue krk_int_from_float(double val);
FUNC_SIG(int,__init__) {
static __attribute__ ((unused)) const char* _method_name = "__init__";
METHOD_TAKES_AT_MOST(2);
if (argc < 2) return INTEGER_VAL(0);
if (IS_BOOLEAN(argv[1])) return INTEGER_VAL(AS_INTEGER(argv[1]));
if (IS_INTEGER(argv[1])) return argv[1];
if (IS_STRING(argv[1])) {
krk_integer_type _base = 10;
if (argc > 2) {
CHECK_ARG(2,int,krk_integer_type,base);
_base = base;
}
if (unlikely(_base < 0 || _base == 1 || _base > 36)) return krk_runtimeError(vm.exceptions->valueError, "base must be 0 or between 2 and 36");
KrkValue result = krk_parse_int(AS_CSTRING(argv[1]), AS_STRING(argv[1])->length, _base);
KRK_StaticMethod(int,__new__) {
KrkObj *cls;
int has_x = 0;
KrkValue x = NONE_VAL();
int has_base = 0;
int base = 10;
/* Most common case */
if (!hasKw && argc == 2) {
x = argv[1];
goto _just_x;
}
if (!krk_parseArgs("O|V?i?:int", (const char*[]){"","","base"},
&cls, &has_x, &x, &has_base, &base)) return NONE_VAL();
if (has_base && (base < 2 || base > 36) && base != 0) {
return krk_runtimeError(vm.exceptions->valueError, "base must be 0 or between 2 and 36");
}
if (!has_x && has_base) {
return krk_runtimeError(vm.exceptions->typeError, "missing str argument");
}
if (!has_x) {
return INTEGER_VAL(0);
}
if (has_base && !IS_STRING(x)) {
return krk_runtimeError(vm.exceptions->typeError, "can not convert non-str with explicit base");
}
_just_x:
if (IS_INTEGER(x)) return INTEGER_VAL(AS_INTEGER(x));
#ifndef KRK_NO_FLOAT
if (IS_FLOATING(x)) return krk_int_from_float(AS_FLOATING(x));
#endif
if (IS_STRING(x)) {
KrkValue result = krk_parse_int(AS_CSTRING(x), AS_STRING(x)->length, base);
if (IS_NONE(result)) {
return krk_runtimeError(vm.exceptions->valueError,
"invalid literal for int() with base %zd: %R", (ssize_t)_base, argv[1]);
"invalid literal for int() with base %zd: %R", (ssize_t)base, x);
}
return result;
}
if (IS_FLOATING(argv[1])) return krk_int_from_float(AS_FLOATING(argv[1]));
if (IS_BOOLEAN(argv[1])) return INTEGER_VAL(AS_BOOLEAN(argv[1]));
return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "int", argv[1]);
if (krk_isInstanceOf(x, KRK_BASE_CLASS(long))) return x;
return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "int", x);
}
KRK_Method(int,__str__) {
KRK_Method(int,__repr__) {
char tmp[100];
size_t l = snprintf(tmp, 100, PRIkrk_int, self);
return OBJECT_VAL(krk_copyString(tmp, l));
}
KRK_Method(int,__int__) { return argv[0]; }
#ifndef KRK_NO_FLOAT
KRK_Method(int,__float__) { return FLOATING_VAL(self); }
#endif
KRK_Method(int,__chr__) {
unsigned char bytes[5] = {0};
@ -59,7 +89,9 @@ KRK_Method(int,__chr__) {
KRK_Method(int,__eq__) {
METHOD_TAKES_EXACTLY(1);
if (likely(IS_INTEGER(argv[1]))) return BOOLEAN_VAL(self == AS_INTEGER(argv[1]));
#ifndef KRK_NO_FLOAT
else if (IS_FLOATING(argv[1])) return BOOLEAN_VAL(self == AS_FLOATING(argv[1]));
#endif
return NOTIMPL_VAL();
}
@ -211,7 +243,7 @@ KrkValue krk_doFormatString(const char * typeName, KrkString * format_spec, int
if ((!positive || opts.sign == '+') && width > 1) width--;
int digits = 0;
int sepcount = opts.sep == ',' ? 3 : 4;
int sepcount = (opts.sep == ',' || base == 10) ? 3 : 4;
int more = 0;
if (prepCallback) callback = prepCallback(abs, base);
@ -337,15 +369,21 @@ OVERFLOW_CHECKED_INT_OPERATION(add,+)
OVERFLOW_CHECKED_INT_OPERATION(sub,-)
OVERFLOW_CHECKED_INT_OPERATION(mul,*)
#ifndef KRK_NO_FLOAT
# define MAYBE_FLOAT(x) x
#else
# define MAYBE_FLOAT(x) krk_runtimeError(vm.exceptions->valueError, "no float support")
#endif
#define BASIC_BIN_OP(name,operator) \
KRK_Method(int,__ ## name ## __) { \
if (likely(IS_INTEGER(argv[1]))) return krk_int_op_ ## name(self, AS_INTEGER(argv[1])); \
else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL((double)self operator AS_FLOATING(argv[1])); \
else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(FLOATING_VAL((double)self operator AS_FLOATING(argv[1]))); \
return NOTIMPL_VAL(); \
} \
KRK_Method(int,__r ## name ## __) { \
if (likely(IS_INTEGER(argv[1]))) return krk_int_op_ ## name(AS_INTEGER(argv[1]), self); \
else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(AS_FLOATING(argv[1]) operator (double)self); \
else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(FLOATING_VAL(AS_FLOATING(argv[1]) operator (double)self)); \
return NOTIMPL_VAL(); \
}
@ -362,7 +400,7 @@ OVERFLOW_CHECKED_INT_OPERATION(mul,*)
#define COMPARE_OP(name,operator) \
KRK_Method(int,__ ## name ## __) { \
if (likely(IS_INTEGER(argv[1]))) return BOOLEAN_VAL(self operator AS_INTEGER(argv[1])); \
else if (likely(IS_FLOATING(argv[1]))) return BOOLEAN_VAL((double)self operator AS_FLOATING(argv[1])); \
else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(BOOLEAN_VAL((double)self operator AS_FLOATING(argv[1]))); \
return NOTIMPL_VAL(); \
}
@ -397,6 +435,7 @@ COMPARE_OP(ge, >=)
#undef INT_ONLY_BIN_OP
#undef COMPARE_OP
#ifndef KRK_NO_FLOAT
KRK_Method(int,__truediv__) {
METHOD_TAKES_EXACTLY(1);
if (likely(IS_INTEGER(argv[1]))) {
@ -418,6 +457,7 @@ KRK_Method(int,__rtruediv__) {
else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(AS_FLOATING(argv[1]) / (double)self);
return NOTIMPL_VAL();
}
#endif
#ifdef __TINYC__
#include <math.h>
@ -477,9 +517,13 @@ KRK_Method(int,__floordiv__) {
if (likely(IS_INTEGER(argv[1]))) {
return _krk_int_div(self,AS_INTEGER(argv[1]));
} else if (likely(IS_FLOATING(argv[1]))) {
#ifndef KRK_NO_FLOAT
double b = AS_FLOATING(argv[1]);
if (unlikely(b == 0.0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "float division by zero");
return FLOATING_VAL(__builtin_floor((double)self / b));
#else
return krk_runtimeError(vm.exceptions->valueError, "no float support");
#endif
}
return NOTIMPL_VAL();
}
@ -488,7 +532,7 @@ KRK_Method(int,__rfloordiv__) {
METHOD_TAKES_EXACTLY(1);
if (unlikely(self == 0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "integer division by zero");
else if (likely(IS_INTEGER(argv[1]))) return _krk_int_div(AS_INTEGER(argv[1]), self);
else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(__builtin_floor(AS_FLOATING(argv[1]) / (double)self));
else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(FLOATING_VAL(__builtin_floor(AS_FLOATING(argv[1]) / (double)self)));
return NOTIMPL_VAL();
}
@ -567,9 +611,9 @@ KRK_Method(int,__pos__) {
} \
} while (0)
FUNC_SIG(float,__init__) {
static __attribute__ ((unused)) const char* _method_name = "__init__";
METHOD_TAKES_AT_MOST(1);
#ifndef KRK_NO_FLOAT
KRK_StaticMethod(float,__new__) {
FUNCTION_TAKES_AT_MOST(2);
if (argc < 2) return FLOATING_VAL(0.0);
if (IS_FLOATING(argv[1])) return argv[1];
if (IS_INTEGER(argv[1])) return FLOATING_VAL(AS_INTEGER(argv[1]));
@ -580,24 +624,94 @@ FUNC_SIG(float,__init__) {
return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "float", argv[1]);
}
KRK_Method(float,__int__) { return INTEGER_VAL(self); }
KRK_Method(float,__int__) { return krk_int_from_float(self); }
KRK_Method(float,__float__) { return argv[0]; }
static int isDigits(const char * c) {
while (*c) {
if (*c != '-' && (*c < '0' || *c > '9')) return 0;
c++;
}
return 1;
extern KrkValue krk_double_to_string(double,unsigned int,char,int,int);
KRK_Method(float,__repr__) {
return krk_double_to_string(self,16,' ',0,0);
}
KRK_Method(float,__str__) {
char tmp[100];
size_t l = snprintf(tmp, 97, "%.16g", self);
if (!strstr(tmp,".") && isDigits(tmp)) {
l = snprintf(tmp,100,"%.16g.0",self);
KRK_Method(float,__format__) {
char * format_spec;
size_t format_spec_length;
if (!krk_parseArgs(".s#", (const char*[]){"format_spec"}, &format_spec, &format_spec_length)) return NONE_VAL();
struct ParsedFormatSpec opts = {0};
const char * spec = krk_parseCommonFormatSpec(&opts, format_spec, format_spec_length);
if (!spec) return NONE_VAL();
char formatter = 'g';
int digits = 16;
int forcedigits = opts.alt;
switch (*spec) {
case 0:
case 'g':
/* defaults */
break;
case 'G':
formatter = 'G';
break;
case 'f':
case 'F':
case 'e':
case 'E':
digits = 6;
formatter = *spec;
forcedigits = 1;
break;
default:
return krk_runtimeError(vm.exceptions->valueError,
"Unknown format code '%c' for object of type '%s'",
*spec,
"float");
}
return OBJECT_VAL(krk_copyString(tmp, l));
if (opts.sep) return krk_runtimeError(vm.exceptions->valueError, "unsupported option for float");
if (opts.hasPrecision) digits = opts.prec;
if (!opts.align) opts.align = '>';
KrkValue result = krk_double_to_string(self, digits, formatter, opts.sign == '+', forcedigits);
if (!IS_STRING(result) || !opts.width) return result;
krk_push(result);
/* Calculate how much padding we need to add. */
size_t avail = (size_t)opts.width > AS_STRING(result)->length ? (size_t)opts.width - AS_STRING(result)->length : 0;
/* If there's no available space for padding, just return the string we already have. */
if (!avail) return krk_pop();
struct StringBuilder sb = {0};
size_t before = 0;
size_t after = 0;
int hassign = 0;
if (opts.align == '<') {
after = avail;
} else if (opts.align == '>') {
before = avail;
} else if (opts.align == '^') {
after = avail / 2;
before = avail - after;
} else if (opts.align == '=') {
before = avail;
if (avail && AS_STRING(result)->length && (AS_CSTRING(result)[0] == '-' || AS_CSTRING(result)[0] == '+')) {
krk_pushStringBuilder(&sb, AS_CSTRING(result)[0]);
hassign = 1;
}
}
/* Fill in padding with a new string builder. */
for (size_t i = 0; i < before; ++i) krk_pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
krk_pushStringBuilderStr(&sb, AS_CSTRING(result) + hassign, AS_STRING(result)->length - hassign);
for (size_t i = 0; i < after; ++i) krk_pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
krk_pop();
return krk_finishStringBuilder(&sb);
}
KRK_Method(float,__eq__) {
@ -700,26 +814,42 @@ KRK_Method(float,__pos__) {
return argv[0];
}
extern KrkValue krk_float_to_fraction(double d);
KRK_Method(float,as_integer_ratio) {
return krk_float_to_fraction(self);
}
#endif
#undef CURRENT_CTYPE
#define CURRENT_CTYPE krk_integer_type
FUNC_SIG(bool,__init__) {
static __attribute__ ((unused)) const char* _method_name = "__init__";
METHOD_TAKES_AT_MOST(1);
KRK_StaticMethod(bool,__new__) {
FUNCTION_TAKES_AT_MOST(2);
if (argc < 2) return BOOLEAN_VAL(0);
return BOOLEAN_VAL(!krk_isFalsey(argv[1]));
}
KRK_Method(bool,__str__) {
KRK_Method(bool,__repr__) {
return OBJECT_VAL((self ? S("True") : S("False")));
}
FUNC_SIG(NoneType,__init__) {
KRK_Method(bool,__format__) {
METHOD_TAKES_EXACTLY(1);
CHECK_ARG(1,str,KrkString*,format_spec);
if (!format_spec->length) {
return FUNC_NAME(bool,__repr__)(argc,argv,hasKw);
} else {
return FUNC_NAME(int,__format__)(argc,argv,hasKw);
}
}
KRK_StaticMethod(NoneType,__new__) {
if (argc > 1) return krk_runtimeError(vm.exceptions->argumentError, "%s takes no arguments", "NoneType");
return NONE_VAL();
}
KRK_Method(NoneType,__str__) {
KRK_Method(NoneType,__repr__) {
return OBJECT_VAL(S("None"));
}
@ -736,12 +866,12 @@ KRK_Method(NoneType,__eq__) {
#define IS_NotImplementedType(o) IS_NOTIMPL(o)
#define AS_NotImplementedType(o) (1)
FUNC_SIG(NotImplementedType,__init__) {
KRK_StaticMethod(NotImplementedType,__new__) {
if (argc > 1) return krk_runtimeError(vm.exceptions->argumentError, "%s takes no arguments", "NotImplementedType");
return NOTIMPL_VAL();
}
KRK_Method(NotImplementedType,__str__) {
KRK_Method(NotImplementedType,__repr__) {
return OBJECT_VAL(S("NotImplemented"));
}
@ -756,8 +886,10 @@ KRK_Method(NotImplementedType,__eq__) {
}
#undef BIND_METHOD
#undef BIND_STATICMETHOD
/* These class names conflict with C types, so we need to cheat a bit */
#define BIND_METHOD(klass,method) do { krk_defineNative(& _ ## klass->methods, #method, _ ## klass ## _ ## method); } while (0)
#define BIND_STATICMETHOD(klass,method) do { krk_defineNativeStaticMethod(& _ ## klass->methods, #method, _ ## klass ## _ ## method); } while (0)
#define BIND_TRIPLET(klass,name) \
BIND_METHOD(klass,__ ## name ## __); \
BIND_METHOD(klass,__r ## name ## __); \
@ -766,11 +898,11 @@ _noexport
void _createAndBind_numericClasses(void) {
KrkClass * _int = ADD_BASE_CLASS(vm.baseClasses->intClass, "int", vm.baseClasses->objectClass);
_int->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_METHOD(int,__init__);
BIND_METHOD(int,__str__);
_int->allocSize = 0;
BIND_STATICMETHOD(int,__new__);
BIND_METHOD(int,__repr__);
BIND_METHOD(int,__int__);
BIND_METHOD(int,__chr__);
BIND_METHOD(int,__float__);
BIND_METHOD(int,__eq__);
BIND_METHOD(int,__hash__);
BIND_METHOD(int,__format__);
@ -784,10 +916,14 @@ void _createAndBind_numericClasses(void) {
BIND_TRIPLET(int,lshift);
BIND_TRIPLET(int,rshift);
BIND_TRIPLET(int,mod);
BIND_TRIPLET(int,truediv);
BIND_TRIPLET(int,floordiv);
BIND_TRIPLET(int,pow);
#ifndef KRK_NO_FLOAT
BIND_METHOD(int,__float__);
BIND_TRIPLET(int,truediv);
#endif
BIND_METHOD(int,__lt__);
BIND_METHOD(int,__gt__);
BIND_METHOD(int,__le__);
@ -801,16 +937,17 @@ void _createAndBind_numericClasses(void) {
BIND_METHOD(int,__abs__);
BIND_METHOD(int,__pos__);
krk_defineNative(&_int->methods, "__repr__", FUNC_NAME(int,__str__));
krk_finalizeClass(_int);
KRK_DOC(_int, "Convert a number or string type to an integer representation.");
KrkClass * _float = ADD_BASE_CLASS(vm.baseClasses->floatClass, "float", vm.baseClasses->objectClass);
_float->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_METHOD(float,__init__);
_float->allocSize = 0;
#ifndef KRK_NO_FLOAT
BIND_STATICMETHOD(float,__new__);
BIND_METHOD(float,__int__);
BIND_METHOD(float,__float__);
BIND_METHOD(float,__str__);
BIND_METHOD(float,__repr__);
BIND_METHOD(float,__eq__);
BIND_METHOD(float,__hash__);
BIND_TRIPLET(float,add);
@ -825,34 +962,36 @@ void _createAndBind_numericClasses(void) {
BIND_METHOD(float,__neg__);
BIND_METHOD(float,__abs__);
BIND_METHOD(float,__pos__);
krk_defineNative(&_float->methods, "__repr__", FUNC_NAME(float,__str__));
BIND_METHOD(float,__format__);
BIND_METHOD(float,as_integer_ratio);
#endif
krk_finalizeClass(_float);
KRK_DOC(_float, "Convert a number or string type to a float representation.");
KrkClass * _bool = ADD_BASE_CLASS(vm.baseClasses->boolClass, "bool", vm.baseClasses->intClass);
_bool->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_METHOD(bool,__init__);
BIND_METHOD(bool,__str__);
krk_defineNative(&_bool->methods, "__repr__", FUNC_NAME(bool,__str__));
BIND_STATICMETHOD(bool,__new__);
BIND_METHOD(bool,__repr__);
BIND_METHOD(bool,__format__);
krk_finalizeClass(_bool);
KRK_DOC(_bool, "Returns False if the argument is 'falsey', otherwise True.");
KrkClass * _NoneType = ADD_BASE_CLASS(vm.baseClasses->noneTypeClass, "NoneType", vm.baseClasses->objectClass);
_NoneType->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_METHOD(NoneType, __init__);
BIND_METHOD(NoneType, __str__);
_NoneType->allocSize = 0;
BIND_STATICMETHOD(NoneType, __new__);
BIND_METHOD(NoneType, __repr__);
BIND_METHOD(NoneType, __hash__);
BIND_METHOD(NoneType, __eq__);
krk_defineNative(&_NoneType->methods, "__repr__", FUNC_NAME(NoneType,__str__));
krk_finalizeClass(_NoneType);
KrkClass * _NotImplementedType = ADD_BASE_CLASS(vm.baseClasses->notImplClass, "NotImplementedType", vm.baseClasses->objectClass);
_NotImplementedType->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_METHOD(NotImplementedType, __init__);
BIND_METHOD(NotImplementedType, __str__);
_NotImplementedType->allocSize = 0;
BIND_STATICMETHOD(NotImplementedType, __new__);
BIND_METHOD(NotImplementedType, __repr__);
BIND_METHOD(NotImplementedType, __hash__);
BIND_METHOD(NotImplementedType, __eq__);
krk_defineNative(&_NotImplementedType->methods, "__repr__", FUNC_NAME(NotImplementedType,__str__));
krk_finalizeClass(_NotImplementedType);
krk_attachNamedValue(&vm.builtins->fields, "NotImplemented", NOTIMPL_VAL());

View File

@ -54,7 +54,7 @@ KRK_Method(range,__init__) {
self->step = _step;
}
}
return argv[0];
return NONE_VAL();
}
KRK_Method(range,__repr__) {
@ -79,6 +79,22 @@ KRK_Method(range,__iter__) {
return OBJECT_VAL(output);
}
KRK_Method(range,__contains__) {
int i;
if (!krk_parseArgs(".i", (const char*[]){"i"}, &i)) return NONE_VAL();
if (self->step == 1) return BOOLEAN_VAL(i >= self->min && i < self->max);
if (self->step == -1) return BOOLEAN_VAL(i <= self->min && i > self->max);
if (self->step > 0) {
if (i >= self->max || i < self->min) return BOOLEAN_VAL(0);
if ((i - self->min) % self->step) return BOOLEAN_VAL(0);
return BOOLEAN_VAL(1);
} else {
if (i <= self->max || i > self->min) return BOOLEAN_VAL(0);
if ((i - self->min) % -self->step) return BOOLEAN_VAL(0);
return BOOLEAN_VAL(1);
}
}
#undef CURRENT_CTYPE
#define CURRENT_CTYPE struct RangeIterator *
@ -90,7 +106,7 @@ KRK_Method(rangeiterator,__init__) {
self->i = i;
self->max = max;
self->step = step;
return argv[0];
return NONE_VAL();
}
KRK_Method(rangeiterator,__call__) {
@ -117,6 +133,7 @@ void _createAndBind_rangeClass(void) {
"With three arguments, a @p step may also be included.");
BIND_METHOD(range,__iter__);
BIND_METHOD(range,__repr__);
BIND_METHOD(range,__contains__);
KRK_DOC(range, "@brief Iterable object that produces sequential numeric values.");
krk_finalizeClass(range);

View File

@ -58,18 +58,18 @@ KRK_Method(set,__init__) {
if (argc == 2) {
if (krk_unpackIterable(argv[1], self, _set_init_callback)) return NONE_VAL();
}
return argv[0];
return NONE_VAL();
}
KRK_Method(set,__contains__) {
METHOD_TAKES_EXACTLY(1);
KrkValue _unused;
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &_unused));
KrkValue v;
return BOOLEAN_VAL(krk_tableGet(&self->entries, argv[1], &v));
}
KRK_Method(set,__repr__) {
METHOD_TAKES_NONE();
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL("{...}");
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL(S("{...}"));
if (!self->entries.capacity) return OBJECT_VAL(S("set()"));
((KrkObj*)self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
struct StringBuilder sb = {0};
@ -80,22 +80,19 @@ KRK_Method(set,__repr__) {
for (size_t i = 0; i < len; ++i) {
KrkTableEntry * entry = &self->entries.entries[i];
if (IS_KWARGS(entry->key)) continue;
if (c > 0) {
pushStringBuilderStr(&sb, ", ", 2);
}
if (c) pushStringBuilderStr(&sb, ", ", 2);
c++;
KrkClass * type = krk_getType(entry->key);
krk_push(entry->key);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
if (!krk_pushStringBuilderFormat(&sb, "%R", entry->key)) goto _error;
}
pushStringBuilder(&sb,'}');
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
return finishStringBuilder(&sb);
_error:
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
krk_discardStringBuilder(&sb);
return NONE_VAL();
}
KRK_Method(set,__and__) {
@ -198,11 +195,11 @@ KRK_Method(set,__eq__) {
if (self->entries.count != them->entries.count)
return BOOLEAN_VAL(0);
KrkValue _unused;
KrkValue v;
for (unsigned int i = 0; i < self->entries.capacity; ++i) {
if (IS_KWARGS(self->entries.entries[i].key)) continue;
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
@ -216,10 +213,10 @@ KRK_Method(set,__lt__) {
struct Set * them = AS_set(argv[1]);
if (self->entries.count == them->entries.count)
return BOOLEAN_VAL(0);
KrkValue _unused;
KrkValue v;
for (unsigned int i = 0; i < self->entries.capacity; ++i) {
if (IS_KWARGS(self->entries.entries[i].key)) continue;
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
@ -230,10 +227,10 @@ KRK_Method(set,__le__) {
if (!IS_set(argv[1]))
return NOTIMPL_VAL();
struct Set * them = AS_set(argv[1]);
KrkValue _unused;
KrkValue v;
for (unsigned int i = 0; i < self->entries.capacity; ++i) {
if (IS_KWARGS(self->entries.entries[i].key)) continue;
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&them->entries, self->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
@ -246,10 +243,10 @@ KRK_Method(set,__gt__) {
struct Set * them = AS_set(argv[1]);
if (self->entries.count == them->entries.count)
return BOOLEAN_VAL(0);
KrkValue _unused;
KrkValue v;
for (unsigned int i = 0; i < them->entries.capacity; ++i) {
if (IS_KWARGS(them->entries.entries[i].key)) continue;
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
@ -259,10 +256,10 @@ KRK_Method(set,__ge__) {
if (!IS_set(argv[1]))
return NOTIMPL_VAL();
struct Set * them = AS_set(argv[1]);
KrkValue _unused;
KrkValue v;
for (unsigned int i = 0; i < them->entries.capacity; ++i) {
if (IS_KWARGS(them->entries.entries[i].key)) continue;
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &_unused)) return BOOLEAN_VAL(0);
if (!krk_tableGet(&self->entries, them->entries.entries[i].key, &v)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
@ -294,6 +291,18 @@ KRK_Method(set,clear) {
return NONE_VAL();
}
KRK_Method(set,update) {
METHOD_TAKES_AT_MOST(1);
if (argc > 1) {
if (IS_set(argv[1])) {
krk_tableAddAll(&AS_set(argv[1])->entries, &self->entries);
} else {
if (krk_unpackIterable(argv[1], self, _set_init_callback)) return NONE_VAL();
}
}
return NONE_VAL();
}
FUNC_SIG(setiterator,__init__);
KRK_Method(set,__iter__) {
@ -312,7 +321,7 @@ KRK_Method(setiterator,__init__) {
CHECK_ARG(1,set,void*,source);
self->set = argv[1];
self->i = 0;
return argv[0];
return NONE_VAL();
}
KRK_Method(setiterator,__call__) {
@ -378,7 +387,7 @@ void _createAndBind_setClass(void) {
KRK_DOC(BIND_METHOD(set,clear),
"@brief Empty the set.\n\n"
"Removes all elements from the set, in-place.");
krk_defineNative(&set->methods, "__str__", FUNC_NAME(set,__repr__));
BIND_METHOD(set,update);
krk_attachNamedValue(&set->methods, "__hash__", NONE_VAL());
krk_finalizeClass(set);

View File

@ -112,42 +112,30 @@ KRK_Method(slice,__init__) {
self->step = NONE_VAL();
}
}
return argv[0];
return NONE_VAL();
}
KRK_Method(slice,__repr__) {
METHOD_TAKES_NONE();
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL("slice(...)");
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL(S("slice(...)"));
((KrkObj*)self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
struct StringBuilder sb = {0};
pushStringBuilderStr(&sb,"slice(",6);
KrkClass * type;
KrkValue result;
/* start */
type = krk_getType(self->start);
krk_push(self->start);
result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
if (!krk_pushStringBuilderFormat(&sb, "%R", self->start)) goto _error;
pushStringBuilderStr(&sb,", ",2);
/* end */
type = krk_getType(self->end);
krk_push(self->end);
result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
if (!krk_pushStringBuilderFormat(&sb, "%R", self->end)) goto _error;
pushStringBuilderStr(&sb,", ",2);
/* step */
type = krk_getType(self->step);
krk_push(self->step);
result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
if (!krk_pushStringBuilderFormat(&sb, "%R", self->step)) goto _error;
pushStringBuilder(&sb,')');
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
return finishStringBuilder(&sb);
_error:
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
krk_discardStringBuilder(&sb);
return NONE_VAL();
}
KRK_Method(slice,start) {
@ -165,9 +153,30 @@ KRK_Method(slice,step) {
return self->step;
}
#undef CURRENT_CTYPE
#define CURRENT_CTYPE KrkInstance *
#define IS_ellipsis(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(ellipsis)))
#define AS_ellipsis(o) ((KrkInstance*)AS_INSTANCE(o))
KRK_StaticMethod(ellipsis,__new__) {
KrkClass * _class = NULL;
if (!krk_parseArgs("O!", (const char*[]){"cls"}, KRK_BASE_CLASS(type), &_class)) return NONE_VAL();
if (!krk_isSubClass(_class, KRK_BASE_CLASS(ellipsis))) {
return krk_runtimeError(vm.exceptions->typeError, "%S is not a subclass of %S", _class->name, KRK_BASE_CLASS(ellipsis)->name);
}
KrkValue out;
if (!krk_tableGet_fast(&vm.builtins->fields, S("Ellipsis"), &out)) return krk_runtimeError(vm.exceptions->typeError, "Ellipsis is missing");
return out;
}
KRK_Method(ellipsis,__repr__) {
return OBJECT_VAL(S("Ellipsis"));
}
_noexport
void _createAndBind_sliceClass(void) {
KrkClass * slice = ADD_BASE_CLASS(vm.baseClasses->sliceClass, "slice", vm.baseClasses->objectClass);
KrkClass * slice = ADD_BASE_CLASS(KRK_BASE_CLASS(slice), "slice", KRK_BASE_CLASS(object));
slice->allocSize = sizeof(struct KrkSlice);
slice->_ongcscan = _slice_gcscan;
slice->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
@ -176,7 +185,14 @@ void _createAndBind_sliceClass(void) {
BIND_PROP(slice,start);
BIND_PROP(slice,end);
BIND_PROP(slice,step);
krk_defineNative(&slice->methods, "__str__", FUNC_NAME(slice,__repr__));
krk_attachNamedValue(&slice->methods, "__hash__", NONE_VAL());
krk_finalizeClass(slice);
KrkClass * ellipsis = ADD_BASE_CLASS(KRK_BASE_CLASS(ellipsis), "ellipsis", KRK_BASE_CLASS(object));
krk_attachNamedObject(&vm.builtins->fields, "Ellipsis", (KrkObj*)krk_newInstance(ellipsis));
ellipsis->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_STATICMETHOD(ellipsis,__new__);
BIND_METHOD(ellipsis,__repr__);
krk_finalizeClass(ellipsis);
}

View File

@ -27,12 +27,12 @@ KRK_Method(str,__ord__) {
return INTEGER_VAL(krk_unicodeCodepoint(self,0));
}
KRK_Method(str,__init__) {
KRK_StaticMethod(str,__new__) {
/* Ignore argument which would have been an instance */
if (argc < 2) {
return OBJECT_VAL(S(""));
}
METHOD_TAKES_AT_MOST(1);
FUNCTION_TAKES_AT_MOST(2);
if (IS_STRING(argv[1])) return argv[1]; /* strings are immutable, so we can just return the arg */
/* Find the type of arg */
krk_push(argv[1]);
@ -56,7 +56,7 @@ KRK_Method(str,__add__) {
bl = them->length;
size_t length = al + bl;
char * chars = ALLOCATE(char, length + 1);
char * chars = KRK_ALLOCATE(char, length + 1);
memcpy(chars, a, al);
memcpy(chars + al, b, bl);
chars[length] = '\0';
@ -101,7 +101,11 @@ KRK_Method(str,__int__) {
/* str.__float__() */
KRK_Method(str,__float__) {
METHOD_TAKES_NONE();
return FLOATING_VAL(strtod(AS_CSTRING(argv[0]),NULL));
#ifndef KRK_NO_FLOAT
return krk_parse_float(AS_CSTRING(argv[0]),AS_STRING(argv[0])->length);
#else
return krk_runtimeError(vm.exceptions->valueError, "no float support");
#endif
}
KRK_Method(str,__getitem__) {
@ -586,8 +590,10 @@ KRK_Method(str,__mod__) {
if (IS_INTEGER(arg)) {
krk_push(INTEGER_VAL(AS_INTEGER(arg)));
#ifndef KRK_NO_FLOAT
} else if (IS_FLOATING(arg)) {
krk_push(INTEGER_VAL(AS_FLOATING(arg)));
#endif
} else {
krk_runtimeError(vm.exceptions->typeError, "%%i format: a number is required, not '%T'", arg);
goto _exception;
@ -819,17 +825,47 @@ KRK_Method(str,index) {
}
KRK_Method(str,startswith) {
METHOD_TAKES_EXACTLY(1); /* I know the Python versions of these take optional start, end... */
CHECK_ARG(1,str,KrkString*,prefix);
return BOOLEAN_VAL(substringMatch(self->chars,self->length,prefix->chars,prefix->length));
KrkString * substr;
int start = 0;
int end = self->codesLength;
if (!krk_parseArgs(".O!|ii",(const char*[]){"prefix","start","end"}, KRK_BASE_CLASS(str), &substr, &start, &end)) {
return NONE_VAL();
}
WRAP_INDEX(start);
WRAP_INDEX(end);
krk_unicodeString(self);
krk_unicodeString(substr);
if (end < start || (size_t)(end - start) < substr->codesLength) return BOOLEAN_VAL(0);
for (size_t i = 0; i < substr->codesLength; ++i) {
if (KRK_STRING_FAST(self, start + i) != KRK_STRING_FAST(substr,i)) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
KRK_Method(str,endswith) {
METHOD_TAKES_EXACTLY(1); /* I know the Python versions of these take optional start, end... */
CHECK_ARG(1,str,KrkString*,suffix);
if (suffix->length > self->length) return BOOLEAN_VAL(0);
return BOOLEAN_VAL(substringMatch(self->chars + (self->length - suffix->length),
suffix->length, suffix->chars, suffix->length));
KrkString * substr;
int start = 0;
int end = self->codesLength;
if (!krk_parseArgs(".O!|ii",(const char*[]){"suffix","start","end"}, KRK_BASE_CLASS(str), &substr, &start, &end)) {
return NONE_VAL();
}
WRAP_INDEX(start);
WRAP_INDEX(end);
krk_unicodeString(self);
krk_unicodeString(substr);
if (end < start || (size_t)(end - start) < substr->codesLength) return BOOLEAN_VAL(0);
for (size_t i = 0; i < substr->codesLength; ++i) {
if (KRK_STRING_FAST(self, (end - i - 1)) != KRK_STRING_FAST(substr,(substr->codesLength - i - 1))) return BOOLEAN_VAL(0);
}
return BOOLEAN_VAL(1);
}
/**
@ -856,33 +892,35 @@ KRK_Method(str,__repr__) {
pushStringBuilder(&sb, quote);
for (char * c = AS_CSTRING(argv[0]); c < end; ++c) {
switch (*c) {
unsigned char ch = *c;
int addSlash = 0;
switch (ch) {
/* XXX: Other non-printables should probably be escaped as well. */
case '\\': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'\\'); break;
case '\'': if (quote == *c) { pushStringBuilder(&sb,'\\'); } pushStringBuilder(&sb,'\''); break;
case '\"': if (quote == *c) { pushStringBuilder(&sb,'\\'); } pushStringBuilder(&sb,'\"'); break;
case '\a': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'a'); break;
case '\b': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'b'); break;
case '\f': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'f'); break;
case '\n': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'n'); break;
case '\r': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'r'); break;
case '\t': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'t'); break;
case '\v': pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'v'); break;
case 27: pushStringBuilder(&sb,'\\'); pushStringBuilder(&sb,'['); break;
default: {
if ((unsigned char)*c < ' ' || (unsigned char)*c == 0x7F) {
case '\'': addSlash = (quote == ch); ch = '\''; break;
case '\"': addSlash = (quote == ch); ch = '\"'; break;
case '\\': addSlash = 1; ch = '\\'; break;
case '\a': addSlash = 1; ch = 'a'; break;
case '\b': addSlash = 1; ch = 'b'; break;
case '\f': addSlash = 1; ch = 'f'; break;
case '\n': addSlash = 1; ch = 'n'; break;
case '\r': addSlash = 1; ch = 'r'; break;
case '\t': addSlash = 1; ch = 't'; break;
case '\v': addSlash = 1; ch = 'v'; break;
case 27: addSlash = 1; ch = '['; break;
default:
if (ch < ' ' || ch == 0x7F) {
pushStringBuilder(&sb,'\\');
pushStringBuilder(&sb,'x');
char hex[3];
snprintf(hex, 3, "%02x", (unsigned char)*c);
pushStringBuilder(&sb,hex[0]);
pushStringBuilder(&sb,hex[1]);
} else {
pushStringBuilder(&sb,*c);
continue;
}
break;
}
}
if (addSlash) krk_pushStringBuilder(&sb,'\\');
krk_pushStringBuilder(&sb,ch);
}
pushStringBuilder(&sb, quote);
@ -1012,7 +1050,8 @@ KRK_Method(striterator,__init__) {
krk_push(OBJECT_VAL(self));
krk_attachNamedObject(&self->fields, "s", (KrkObj*)base);
krk_attachNamedValue(&self->fields, "i", INTEGER_VAL(0));
return krk_pop();
krk_pop();
return NONE_VAL();
}
KRK_Method(striterator,__call__) {
@ -1043,8 +1082,8 @@ _corrupt:
void krk_pushStringBuilder(struct StringBuilder * sb, char c) {
if (sb->capacity < sb->length + 1) {
size_t old = sb->capacity;
sb->capacity = GROW_CAPACITY(old);
sb->bytes = GROW_ARRAY(char, sb->bytes, old, sb->capacity);
sb->capacity = KRK_GROW_CAPACITY(old);
sb->bytes = KRK_GROW_ARRAY(char, sb->bytes, old, sb->capacity);
}
sb->bytes[sb->length++] = c;
}
@ -1054,9 +1093,9 @@ void krk_pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t
size_t prevcap = sb->capacity;
while (sb->capacity < sb->length + len) {
size_t old = sb->capacity;
sb->capacity = GROW_CAPACITY(old);
sb->capacity = KRK_GROW_CAPACITY(old);
}
sb->bytes = GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
sb->bytes = KRK_GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
}
for (size_t i = 0; i < len; ++i) {
sb->bytes[sb->length++] = *(str++);
@ -1064,7 +1103,7 @@ void krk_pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t
}
static void _freeStringBuilder(struct StringBuilder * sb) {
FREE_ARRAY(char,sb->bytes, sb->capacity);
KRK_FREE_ARRAY(char,sb->bytes, sb->capacity);
sb->bytes = NULL;
sb->length = 0;
sb->capacity = 0;
@ -1094,9 +1133,7 @@ int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va
}
/* Bail on exception */
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
return 0;
}
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) break;
++f;
@ -1188,6 +1225,8 @@ int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va
krk_push(res);
if (IS_STRING(res)) {
pushStringBuilderStr(sb, AS_CSTRING(res), AS_STRING(res)->length);
} else if (!(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
krk_runtimeError(vm.exceptions->typeError, "__repr__ returned non-string (type %T)", res);
}
krk_pop();
}
@ -1212,6 +1251,7 @@ int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va
}
}
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return 0;
return 1;
}
@ -1237,7 +1277,8 @@ _noexport
void _createAndBind_strClass(void) {
KrkClass * str = ADD_BASE_CLASS(vm.baseClasses->strClass, "str", vm.baseClasses->objectClass);
str->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
BIND_METHOD(str,__init__);
str->allocSize = 0;
BIND_STATICMETHOD(str,__new__);
BIND_METHOD(str,__iter__);
BIND_METHOD(str,__ord__);
BIND_METHOD(str,__int__);

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) ? GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
positionals->capacity = (count == 1) ? KRK_GROW_CAPACITY(old) : (positionals->count + count);
positionals->values = KRK_GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
}
for (size_t i = 0; i < count; ++i) {
@ -24,21 +24,16 @@ static int _tuple_init_callback(void * context, const KrkValue * values, size_t
return 0;
}
static KrkValue _tuple_init(int argc, const KrkValue argv[], int hasKw) {
KRK_StaticMethod(tuple,__new__) {
METHOD_TAKES_AT_MOST(1);
if (argc == 1) {
return OBJECT_VAL(krk_newTuple(0));
} else if (argc == 2) {
/* Expand argument as an iterable. */
krk_push(OBJECT_VAL(krk_newTuple(0)));
KrkValueArray * positionals = &AS_TUPLE(krk_peek(0))->values;
KrkValue other = argv[1];
krk_unpackIterable(other, positionals, _tuple_init_callback);
return krk_pop();
} else {
return krk_runtimeError(vm.exceptions->argumentError,
"%s() takes %s %d argument%s (%d given)",
"tuple","at most",1,"",argc-1);
}
krk_push(OBJECT_VAL(krk_newTuple(0)));
KrkValueArray * positionals = &AS_TUPLE(krk_peek(0))->values;
KrkValue other = argv[1];
krk_unpackIterable(other, positionals, _tuple_init_callback);
return krk_pop();
}
/* tuple creator */
@ -153,15 +148,8 @@ KRK_Method(tuple,__repr__) {
pushStringBuilder(&sb, '(');
for (size_t i = 0; i < self->values.count; ++i) {
KrkClass * type = krk_getType(self->values.values[i]);
krk_push(self->values.values[i]);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
}
if (i != self->values.count - 1) {
pushStringBuilderStr(&sb, ", ", 2);
}
if (i) pushStringBuilderStr(&sb, ", ", 2);
if (!krk_pushStringBuilderFormat(&sb, "%R", self->values.values[i])) goto _error;
}
if (self->values.count == 1) {
@ -171,6 +159,11 @@ KRK_Method(tuple,__repr__) {
pushStringBuilder(&sb, ')');
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
return finishStringBuilder(&sb);
_error:
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
krk_discardStringBuilder(&sb);
return NONE_VAL();
}
KRK_Method(tuple,__add__) {
@ -273,6 +266,8 @@ _noexport
void _createAndBind_tupleClass(void) {
KrkClass * tuple = ADD_BASE_CLASS(vm.baseClasses->tupleClass, "tuple", vm.baseClasses->objectClass);
tuple->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
tuple->allocSize = 0;
BIND_STATICMETHOD(tuple,__new__);
BIND_METHOD(tuple,__repr__);
BIND_METHOD(tuple,__getitem__);
BIND_METHOD(tuple,__len__);
@ -286,8 +281,6 @@ void _createAndBind_tupleClass(void) {
BIND_METHOD(tuple,__hash__);
BIND_METHOD(tuple,__add__);
BIND_METHOD(tuple,__mul__);
krk_defineNative(&tuple->methods, "__init__", _tuple_init);
krk_defineNative(&tuple->methods, "__str__", FUNC_NAME(tuple,__repr__));
krk_finalizeClass(tuple);
ADD_BASE_CLASS(vm.baseClasses->tupleiteratorClass, "tupleiterator", vm.baseClasses->objectClass);

View File

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

View File

@ -25,16 +25,20 @@ typedef enum {
#define CONSTANT(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
#define OPERAND(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
#define JUMP(opc,sign) OPCODE(opc)
#define COMPLICATED(opc,more) OPCODE(opc)
#define CLOSURE_MORE
#define EXPAND_ARGS_MORE
#define FORMAT_VALUE_MORE
#define LOCAL_MORE
#define OVERLONG_JUMP_MORE
#include "opcodes.h"
#undef SIMPLE
#undef OPERANDB
#undef OPERAND
#undef CONSTANT
#undef JUMP
#undef COMPLICATED
#undef OVERLONG_JUMP_MORE
#undef CLOSURE_MORE
#undef LOCAL_MORE
#undef EXPAND_ARGS_MORE

View File

@ -42,14 +42,14 @@ SIMPLE(OP_EQUAL)
SIMPLE(OP_UNSET)
JUMP(OP_LOOP_ITER,-)
CONSTANT(OP_SET_PROPERTY, NOOP)
SIMPLE(OP_FINALIZE)
SIMPLE(OP_TRY_ELSE)
OPERAND(OP_SET_LOCAL, LOCAL_MORE)
SIMPLE(OP_INVOKE_DELETE)
SIMPLE(OP_RAISE_FROM)
SIMPLE(OP_SHIFTLEFT)
JUMP(OP_POP_JUMP_IF_FALSE,+)
SIMPLE(OP_ANNOTATE)
SIMPLE(OP_FILTER_EXCEPT)
JUMP(OP_FILTER_EXCEPT,+)
SIMPLE(OP_BITAND)
SIMPLE(OP_NONE)
SIMPLE(OP_POP)
@ -75,12 +75,12 @@ SIMPLE(OP_NOT)
OPERAND(OP_CALL, NOOP)
JUMP(OP_PUSH_WITH,+)
SIMPLE(OP_GREATER_EQUAL)
CONSTANT(OP_CLASS_PROPERTY, NOOP)
CONSTANT(OP_SET_NAME, NOOP)
SIMPLE(OP_INPLACE_ADD)
CONSTANT(OP_GET_METHOD, NOOP)
CONSTANT(OP_CLASS,NOOP)
CONSTANT(OP_GET_NAME, NOOP)
SIMPLE(OP_LESS_EQUAL)
SIMPLE(OP_DOCSTRING)
SIMPLE(OP_END_FINALLY)
SIMPLE(OP_MATMUL)
SIMPLE(OP_MODULO)
OPERAND(OP_MAKE_DICT, NOOP)
@ -105,11 +105,22 @@ SIMPLE(OP_INPLACE_POW)
JUMP(OP_YIELD_FROM,+)
OPERAND(OP_MAKE_LIST, NOOP)
OPERAND(OP_GET_LOCAL, LOCAL_MORE)
SIMPLE(OP_END_FINALLY)
SIMPLE(OP_INPLACE_MULTIPLY)
OPERAND(OP_EXPAND_ARGS,EXPAND_ARGS_MORE)
SIMPLE(OP_INHERIT)
JUMP(OP_CALL_ITER,+)
JUMP(OP_JUMP_IF_TRUE_OR_POP,+)
SIMPLE(OP_TRY_ELSE)
OPERAND(OP_MISSING_KW, NOOP)
SIMPLE(OP_LIST_EXTEND_TOP)
SIMPLE(OP_LIST_APPEND_TOP)
SIMPLE(OP_DICT_UPDATE_TOP)
SIMPLE(OP_DICT_SET_TOP)
SIMPLE(OP_SET_UPDATE_TOP)
SIMPLE(OP_SET_ADD_TOP)
SIMPLE(OP_TUPLE_FROM_LIST)
OPERAND(OP_UNPACK_EX,NOOP)
JUMP(OP_ENTER_EXCEPT,+)
SIMPLE(OP_SWAP_POP)
COMPLICATED(OP_OVERLONG_JUMP,OVERLONG_JUMP_MORE)
SIMPLE(OP_PUSH_BUILD_CLASS)

View File

@ -1,29 +1,75 @@
/**
* @brief Function argument parser.
*
* Provides a simple interface for parsing arguments passed to native functions.
*
* This is similar to CPython's PyArg_ParseTupleAndKeywords, and many of the options
* work the same way (though with some exceptions). With the utilities provided here,
* C bindings can parse positional and keyword arguments, with automatic type checking
* and conversion to C types.
*/
#include <kuroko/vm.h>
#include <kuroko/util.h>
/**
* For use with @c ! formats, collects a @c KrkClass* and compares if the arg
* is set. As a special case, the type may be @c NULL in which case failure is
* guaranteed; this allows the standard library to reference potentially
* uninitialized types (like fileio.File which may be uninitialized if the
* module is not loaded, but may still need to be referenced as a potential
* type in a function like @c print ).
* @brief Format a TypeError exception for an argument.
*
* @param method_name Method name from parseVArgs, after possibly modification by `:`
* @param expected Description of expected type; generally a type name, but maybe something like "str of length 1".
* @param arg The value passed that failed the type check.
* @param argName Name of the argument. If NULL or zero-length, argument name is not included in the description.
*/
static int matchType(const char * _method_name, KrkClass * type, KrkValue arg) {
if (arg != KWARGS_VAL(0) && !krk_isInstanceOf(arg, type)) {
krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%T'",
_method_name, type ? type->name->chars : "unknown type", arg);
return 0;
}
return 1;
_cold
static void raise_TypeError(const char * method_name, const char * expected, KrkValue arg, const char * argName) {
krk_runtimeError(vm.exceptions->typeError,
"%s()%s%s expects %s, not '%T'",
method_name, (argName && *argName) ? " argument " : "", (argName && *argName) ? argName : "",
expected, arg);
}
/**
* @brief Get the method name to use for an error message.
*
* If the format string has a ':' it is taken as the start of an alternative method name
* to include in error messages. This may be useful when calling the macro version of
* @c krk_parseArgs in a @c __new__ or @c __init__ method.
*
* @param method_name Original method name passed to krk_parseArgs.
* @param fmt Pointer to somewhere in the format string up to the colon.
*/
_cold
static const char * methodName(const char * method_name, const char * fmt) {
const char * maybeColon = strchr(fmt, ':');
return maybeColon ? maybeColon + 1 : method_name;
}
/* Just to avoid repeating ourselves... */
#define _method_name (methodName(orig_method_name, fmt))
/**
* @brief Extract arguments from kwargs dict, but keep references to them.
*
* Searches for @p argName in the @p kwargs dict. If found, extracts the value
* into @p out and stores a reference to it in @p refList and then deletes
* the original entry from @p kwargs.
*
* @param kwargs Original keyword args dictionary, which will be mutated.
* @param argName Argument name to search for.
* @param out Slot to place argument value in.
* @param refList List to store references for garbage collection.
* @returns Non-zero if the argument was not found.
*/
static int extractKwArg(KrkTable * kwargs, KrkString * argName, KrkValue * out, KrkValueArray * refList) {
if (!krk_tableGet_fast(kwargs, argName, out)) return 1;
krk_writeValueArray(refList, *out);
krk_tableDeleteExact(kwargs, OBJECT_VAL(argName));
return 0;
}
/**
* @brief Validate and parse arguments to a function similar to how managed
* function arguments are handled.
*
* This attempts to emulate CPythons' PyArg_ParseTupleAndKeywords.
*
* This works like a fancy scanf. We accept the original argument specification
* (argc,argv,hasKw), a format string, an array of argument names, and then var
* args that are generally pointers to where to stick results.
@ -37,7 +83,7 @@ static int matchType(const char * _method_name, KrkClass * type, KrkValue arg) {
* @returns 1 on success, 0 on error.
*/
int krk_parseVArgs(
const char * _method_name,
const char * orig_method_name,
int argc, const KrkValue argv[], int hasKw,
const char * fmt, const char ** names, va_list args) {
int iarg = 0; /**< Index into positional input arguments */
@ -58,7 +104,8 @@ int krk_parseVArgs(
}
/* Required args */
for (; *fmt; fmt++) {
while (*fmt) {
if (*fmt == ':') break;
if (*fmt == '|') {
/**
* @c | begins optional arguments - eg. default args. Every format option after
@ -70,6 +117,7 @@ int krk_parseVArgs(
return 1;
}
required = 0;
fmt++;
continue;
}
if (*fmt == '*') {
@ -88,6 +136,7 @@ int krk_parseVArgs(
*out_v = &argv[iarg];
iarg = argc;
required = 0;
fmt++;
continue;
}
if (*fmt == '$') {
@ -103,6 +152,7 @@ int krk_parseVArgs(
return 1;
}
if (iarg < argc) break;
fmt++;
continue;
}
if (*fmt == '~') {
@ -114,34 +164,47 @@ int krk_parseVArgs(
* as for a @c **kwargs argument in a Kuroko function signature.
*/
acceptextrakws = 1;
fmt++;
continue;
}
int wasPositional = 0;
KrkValue arg = KWARGS_VAL(0);
krk_push(OBJECT_VAL(krk_copyString(names[oarg],strlen(names[oarg]))));
if (iarg < argc) {
/* Positional arguments are pretty straightforward. */
arg = argv[iarg];
iarg++;
wasPositional = 1;
} else if ((required && !hasKw) || (hasKw && !krk_tableGet_fast(AS_DICT(argv[argc]), AS_STRING(krk_peek(0)), &arg) && required)) {
} else if ((required && !hasKw) || (hasKw && extractKwArg(AS_DICT(argv[argc]), krk_copyString(names[oarg],strlen(names[oarg])), &arg, AS_LIST(argv[argc+1])) && required)) {
/* If keyword argument lookup failed and this is not an optional argument, raise an exception. */
krk_runtimeError(vm.exceptions->typeError, "%s() missing required positional argument: '%S'",
_method_name, AS_STRING(krk_peek(0)));
krk_runtimeError(vm.exceptions->typeError, "%s() missing required positional argument: '%s'",
_method_name, names[oarg]);
goto _error;
}
if (hasKw && krk_tableDelete(AS_DICT(argv[argc]), krk_peek(0)) && wasPositional) {
/* We remove all arguments from kwargs. If we got this argument from a positional argument,
* and it was found during deletion, we raise a multiple-defs exception. */
krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'",
_method_name, AS_STRING(krk_peek(0)));
goto _error;
char argtype = *fmt++;
if (*fmt == '?') {
/* "is present", useful for things where relying on a default isn't useful but you
* still want to have all the type checking and automatic parsing. */
fmt++;
int * out = va_arg(args, int*);
*out = !krk_valuesSame(arg, KWARGS_VAL(0));
}
switch (*fmt) {
if (*fmt == '!') {
/* "of type", thrown an exception if the argument was present but was not
* an instance of a given class. Originally just for @c O and @c V but
* now available anywhere, though likely not useful for other types.
* Maybe if you want @c p to only be a bool this could be useful? */
fmt++;
KrkClass * type = va_arg(args, KrkClass*);
if (!krk_valuesSame(arg, KWARGS_VAL(0)) && !krk_isInstanceOf(arg, type)) {
raise_TypeError(_method_name, type ? type->name->chars : "unknown type", arg, names[oarg]);
goto _error;
}
}
switch (argtype) {
/**
* @c O Collect an object (with @c ! - of a given type) and place it in
* in the @c KrkObj** var arg. The object must be a heap object,
@ -152,17 +215,12 @@ int krk_parseVArgs(
* before @c None can be evaluated).
*/
case 'O': {
if (fmt[1] == '!') {
fmt++;
KrkClass * type = va_arg(args, KrkClass*);
if (!matchType(_method_name, type, arg)) goto _error;
}
KrkObj ** out = va_arg(args, KrkObj**);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (IS_NONE(arg)) {
*out = NULL;
} else if (!IS_OBJECT(arg)) {
TYPE_ERROR(heap object,arg);
raise_TypeError(_method_name, "heap object", arg, names[oarg]);
goto _error;
} else {
*out = AS_OBJECT(arg);
@ -181,13 +239,8 @@ int krk_parseVArgs(
* error message is less informative in this case.
*/
case 'V': {
if (fmt[1] == '!') {
fmt++;
KrkClass * type = va_arg(args, KrkClass*);
if (!matchType(_method_name, type, arg)) goto _error;
}
KrkValue * out = va_arg(args, KrkValue*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
*out = arg;
}
break;
@ -203,19 +256,19 @@ int krk_parseVArgs(
case 'z': {
char ** out = va_arg(args, char **);
size_t * size = NULL;
if (fmt[1] == '#') {
if (*fmt == '#') {
fmt++;
size = va_arg(args, size_t*);
}
if (arg != KWARGS_VAL(0)) {
if (arg == NONE_VAL()) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (IS_NONE(arg)) {
*out = NULL;
if (size) *size = 0;
} else if (IS_STRING(arg)) {
*out = AS_CSTRING(arg);
if (size) *size = AS_STRING(arg)->length;
} else {
TYPE_ERROR(str or None,arg);
raise_TypeError(_method_name, "str or None", arg, names[oarg]);
goto _error;
}
}
@ -228,16 +281,16 @@ int krk_parseVArgs(
case 's': {
char ** out = va_arg(args, char **);
size_t * size = NULL;
if (fmt[1] == '#') {
if (*fmt == '#') {
fmt++;
size = va_arg(args, size_t*);
}
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (IS_STRING(arg)) {
*out = AS_CSTRING(arg);
if (size) *size = AS_STRING(arg)->length;
} else {
TYPE_ERROR(str,arg);
raise_TypeError(_method_name, "str", arg, names[oarg]);
goto _error;
}
}
@ -253,7 +306,7 @@ int krk_parseVArgs(
* both for future compatibility and to make intent clear, but have no
* functional difference at this point.
*/
#define NUMERIC(c,type) case c: { type * out = va_arg(args, type*); if (arg != KWARGS_VAL(0)) { if (!krk_long_to_int(arg, sizeof(type), out)) goto _error; } break; }
#define NUMERIC(c,type) case c: { type * out = va_arg(args, type*); if (!krk_valuesSame(arg, KWARGS_VAL(0))) { if (!krk_long_to_int(arg, sizeof(type), out)) goto _error; } break; }
NUMERIC('b',unsigned char)
NUMERIC('h',short)
NUMERIC('H',unsigned short)
@ -272,9 +325,9 @@ int krk_parseVArgs(
*/
case 'C': {
int * out = va_arg(args, int*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (!IS_STRING(arg) || AS_STRING(arg)->codesLength != 1) {
TYPE_ERROR(str of length 1,arg);
raise_TypeError(_method_name, "str of length 1", arg, names[oarg]);
goto _error;
}
*out = krk_unicodeCodepoint(AS_STRING(arg),0);
@ -282,15 +335,22 @@ int krk_parseVArgs(
break;
}
#ifndef KRK_NO_FLOAT
/**
* @c f Accept a Kuroko float as C float.
*/
case 'f': {
float * out = va_arg(args, float*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (!IS_FLOATING(arg)) {
TYPE_ERROR(float,arg);
goto _error;
KrkClass * type = krk_getType(arg);
krk_push(arg);
if (!krk_bindMethod(type, S("__float__"))) {
krk_pop();
raise_TypeError(_method_name, "float", arg, names[oarg]);
goto _error;
}
arg = krk_callStack(0);
}
*out = AS_FLOATING(arg);
}
@ -302,15 +362,27 @@ int krk_parseVArgs(
*/
case 'd': {
double * out = va_arg(args, double*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (!IS_FLOATING(arg)) {
TYPE_ERROR(float,arg);
goto _error;
KrkClass * type = krk_getType(arg);
krk_push(arg);
if (!krk_bindMethod(type, S("__float__"))) {
krk_pop();
raise_TypeError(_method_name, "float", arg, names[oarg]);
goto _error;
}
arg = krk_callStack(0);
}
*out = AS_FLOATING(arg);
}
break;
}
#else
case 'f':
case 'd':
krk_runtimeError(vm.exceptions->typeError, "no float support");
goto _error;
#endif
/**
* @c p Accept any value and examine its truthiness, returning an @c int.
@ -320,7 +392,7 @@ int krk_parseVArgs(
*/
case 'p': {
int * out = va_arg(args, int*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
*out = !krk_isFalsey(arg);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _error;
}
@ -328,12 +400,11 @@ int krk_parseVArgs(
}
default: {
krk_runtimeError(vm.exceptions->typeError, "unrecognized directive '%c' in format string", *fmt);
krk_runtimeError(vm.exceptions->typeError, "unrecognized directive '%c' in format string", argtype);
goto _error;
}
}
krk_pop();
oarg++;
}
@ -357,6 +428,15 @@ int krk_parseVArgs(
for (size_t i = 0; i < AS_DICT(argv[argc])->capacity; ++i) {
KrkTableEntry * entry = &AS_DICT(argv[argc])->entries[i];
if (IS_STRING(entry->key)) {
/* See if this was the name of an argument, which means it was already provided as a positional argument. */
for (int j = 0; j < oarg; ++j) {
if (*names[j] && strlen(names[j]) == AS_STRING(entry->key)->length && !strcmp(names[j], AS_CSTRING(entry->key))) {
krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%s'",
_method_name, names[j]);
return 0;
}
}
/* Otherwise just say it was unexpected. */
krk_runtimeError(vm.exceptions->typeError, "%s() got an unexpected keyword argument '%S'",
_method_name, AS_STRING(entry->key));
return 0;
@ -367,7 +447,6 @@ int krk_parseVArgs(
return 1;
_error:
krk_pop(); /* name of argument with error */
return 0;
}
@ -375,12 +454,12 @@ _error:
* @brief Variable argument version of @c krk_parseVArgs.
*/
int krk_parseArgs_impl(
const char * _method_name,
const char * method_name,
int argc, const KrkValue argv[], int hasKw,
const char * format, const char ** names, ...) {
va_list args;
va_start(args, names);
int result = krk_parseVArgs(_method_name,argc,argv,hasKw,format,names,args);
int result = krk_parseVArgs(method_name,argc,argv,hasKw,format,names,args);
va_end(args);
return result;
}

View File

@ -67,3 +67,28 @@ struct ParsedFormatSpec {
* This is the "sdbm" hash. I've been using it in various places for many years,
* and this specific version apparently traces to gawk. */
#define krk_hash_advance(hash,c) do { hash = (int)(c) + (hash << 6) + (hash << 16) - hash; } while (0)
#ifndef KRK_DISABLE_DEBUG
#include <kuroko/debug.h>
struct BreakpointEntry {
KrkCodeObject * inFunction;
size_t offset;
int flags;
uint8_t originalOpcode;
};
#define MAX_BREAKPOINTS 32
struct DebuggerState {
int breakpointsCount;
KrkDebugCallback debuggerHook;
/* XXX This was previously thread-local; it probably should still be
* specific to an individual thread... but we don't really do
* much thread debugging, so... */
int repeatStack_top;
int repeatStack_bottom;
int thisWasForced;
struct BreakpointEntry breakpoints[MAX_BREAKPOINTS];
};
#endif

View File

@ -5,6 +5,7 @@
#include <errno.h>
#include <sys/types.h>
#include <kuroko/kuroko.h>
#include <kuroko/scanner.h>
KrkScanner krk_initScanner(const char * src) {
@ -179,6 +180,12 @@ static KrkToken number(KrkScanner * scanner, char c) {
while (isDigit(peek(scanner))) advance(scanner);
}
if (peek(scanner) == 'e' || peek(scanner) == 'E') {
advance(scanner);
if (peek(scanner) == '+' || peek(scanner) == '-') advance(scanner);
while (isDigit(peek(scanner))) advance(scanner);
}
return makeToken(scanner, TOKEN_NUMBER);
}
@ -349,9 +356,9 @@ KrkToken krk_scanToken(KrkScanner * scanner) {
case '[': return makeToken(scanner, TOKEN_LEFT_SQUARE);
case ']': return makeToken(scanner, TOKEN_RIGHT_SQUARE);
case ',': return makeToken(scanner, TOKEN_COMMA);
case '.': return makeToken(scanner, TOKEN_DOT);
case ';': return makeToken(scanner, TOKEN_SEMICOLON);
case '~': return makeToken(scanner, TOKEN_TILDE);
case '.': return makeToken(scanner, peek(scanner) == '.' ? (peekNext(scanner,1) == '.' ? (advance(scanner), advance(scanner), TOKEN_ELLIPSIS) : TOKEN_DOT) : TOKEN_DOT);
case ':': return makeToken(scanner, match(scanner, '=') ? TOKEN_WALRUS : TOKEN_COLON);
case '!': return makeToken(scanner, match(scanner, '=') ? TOKEN_BANG_EQUAL : TOKEN_BANG);

View File

@ -4,14 +4,14 @@
#include <kuroko/util.h>
#define KRK_VERSION_MAJOR 1
#define KRK_VERSION_MINOR 3
#define KRK_VERSION_PATCH 1
#define KRK_VERSION_LEVEL 0xF
#define KRK_VERSION_SERIAL 0x0
#define KRK_VERSION_MINOR 5
#define KRK_VERSION_PATCH 0
#define KRK_VERSION_LEVEL 0xa
#define KRK_VERSION_SERIAL 0x1
#define KRK_VERSION_EXTRA_BASE ""
#define KRK_VERSION_EXTRA_BASE "a1"
#ifndef STATIC_ONLY
#ifndef KRK_STATIC_ONLY
#define KRK_VERSION_EXTRA KRK_VERSION_EXTRA_BASE
#else
#define KRK_VERSION_EXTRA KRK_VERSION_EXTRA_BASE "-static"
@ -23,6 +23,10 @@
# define KRK_BUILD_COMPILER "GCC " __VERSION__
#elif (defined(__clang__))
# define KRK_BUILD_COMPILER "clang " __clang_version__
#elif (defined(_MSC_VER) && !defined(__clang__))
# define KRK_ARG_STR(str) #str
# define KRK_ARG_LOL(s) KRK_ARG_STR(s)
# define KRK_BUILD_COMPILER "msvc " KRK_ARG_LOL(_MSC_FULL_VER)
#else
# define KRK_BUILD_COMPILER ""
#endif
@ -73,12 +77,15 @@ KRK_Function(getsizeof) {
mySize += sizeof(uint8_t) * self->chunk.capacity;
mySize += sizeof(KrkLineMap) * self->chunk.linesCapacity;
mySize += sizeof(KrkValue) * self->chunk.constants.capacity;
mySize += sizeof(KrkExpressionsMap) * self->expressionsCapacity;
/* requiredArgNames */
mySize += sizeof(KrkValue) * self->positionalArgNames.capacity;
/* keywordArgNames */
mySize += sizeof(KrkValue) * self->keywordArgNames.capacity;
/* Locals array */
mySize += sizeof(KrkLocalEntry) * self->localNameCount;
/* Overlong jumps */
mySize += sizeof(KrkOverlongJump) * self->overlongJumpsCapacity;
break;
}
case KRK_OBJ_NATIVE: {
@ -100,13 +107,13 @@ KRK_Function(getsizeof) {
case KRK_OBJ_CLASS: {
KrkClass * self = AS_CLASS(argv[0]);
mySize += sizeof(KrkClass);
mySize += sizeof(KrkTableEntry) * self->methods.capacity;
mySize += sizeof(KrkTableEntry) * self->subclasses.capacity;
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->methods.capacity;
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->subclasses.capacity;
break;
}
case KRK_OBJ_INSTANCE: {
KrkInstance * self = AS_INSTANCE(argv[0]);
mySize += sizeof(KrkTableEntry) * self->fields.capacity;
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * self->fields.capacity;
KrkClass * type = krk_getType(argv[0]);
mySize += type->allocSize; /* All instance types have an allocSize set */
@ -114,7 +121,7 @@ KRK_Function(getsizeof) {
if (krk_isInstanceOf(argv[0], vm.baseClasses->listClass)) {
mySize += sizeof(KrkValue) * AS_LIST(argv[0])->capacity;
} else if (krk_isInstanceOf(argv[0], vm.baseClasses->dictClass)) {
mySize += sizeof(KrkTableEntry) * AS_DICT(argv[0])->capacity;
mySize += (sizeof(KrkTableEntry) + sizeof(ssize_t)) * AS_DICT(argv[0])->capacity;
}
break;
}
@ -179,6 +186,44 @@ KRK_Function(inspect_value) {
return OBJECT_VAL(krk_newBytes(sizeof(KrkValue),(uint8_t*)&argv[0]));
}
KRK_Function(members) {
KrkValue val;
if (!krk_parseArgs("V", (const char*[]){"obj"}, &val)) return NONE_VAL();
KrkValue myDict = krk_dict_of(0,NULL,0);
krk_push(myDict);
KrkTable * src = NULL;
if (IS_INSTANCE(val) || IS_CLASS(val)) {
src = &AS_INSTANCE(val)->fields;
} else if (IS_CLOSURE(val)) {
src = &AS_CLOSURE(val)->fields;
}
if (src) {
krk_tableAddAll(src, AS_DICT(myDict));
}
return krk_pop();
}
KRK_Function(set_recursion_depth) {
unsigned int maxdepth;
int quiet = 0;
if (!krk_parseArgs("I|p",(const char*[]){"maxdepth","quiet"},&maxdepth,&quiet)) return NONE_VAL();
if (krk_currentThread.exitOnFrame != 0) {
if (quiet) return BOOLEAN_VAL(0);
return krk_runtimeError(vm.exceptions->valueError, "Can not change recursion depth in this context.");
}
krk_setMaximumRecursionDepth(maxdepth);
return BOOLEAN_VAL(1);
}
KRK_Function(get_recursion_depth) {
return INTEGER_VAL(krk_currentThread.maximumCallDepth);
}
void krk_module_init_kuroko(void) {
/**
* kuroko = module()
@ -226,8 +271,14 @@ void krk_module_init_kuroko(void) {
"Removes a module from the module table. It is not necessarily garbage collected if other references to it exist.");
KRK_DOC(BIND_FUNC(vm.system,inspect_value),
"Obtain the memory representation of a stack value.");
KRK_DOC(BIND_FUNC(vm.system,members),
"Obtain a copy of a dict of the direct members of an object.");
KRK_DOC(BIND_FUNC(vm.system,set_recursion_depth),
"Change the maximum recursion depth of the current thread if possible.");
KRK_DOC(BIND_FUNC(vm.system,get_recursion_depth),
"Examine the maximum recursion depth of the current thread.");
krk_attachNamedObject(&vm.system->fields, "module", (KrkObj*)vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(PATH_SEP));
krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(KRK_PATH_SEP));
KrkValue module_paths = krk_list_of(0,NULL,0);
krk_attachNamedValue(&vm.system->fields, "module_paths", module_paths);
krk_writeValueArray(AS_LIST(module_paths), OBJECT_VAL(S("./")));

View File

@ -1,4 +1,23 @@
#include <stdio.h>
/**
* @file table.c
* @brief Ordered hash map.
*
* The original table implementation was derived from CLox. CLox's
* tables only supported string keys, but we support arbitrary values,
* so long as they are hashable.
*
* This implementation maintains the same general API, but take its
* inspiration from CPython to keep insertion order. The "entries"
* table is still an array of key-value pairs, but no longer tracks
* the hash lookup for the map. Instead, the entries array keeps
* a strict insertion ordering, with deleted entries replaced with
* sentinel values representing gaps. A separate "indexes" table
* maps hash slots to their associated key-value pairs, or to -1
* or -2 to represent unused and tombstone slots, respectively.
*
* When resizing a table, the entries array is rewritten and gaps
* are removed. Simultaneously, the new index entries are populated.
*/
#include <string.h>
#include <kuroko/kuroko.h>
#include <kuroko/object.h>
@ -9,16 +28,19 @@
#include <kuroko/threads.h>
#include <kuroko/util.h>
#define TABLE_MAX_LOAD 0.75
#define TABLE_MAX_LOAD 3 / 4
void krk_initTable(KrkTable * table) {
table->count = 0;
table->capacity = 0;
table->used = 0;
table->entries = NULL;
table->indexes = NULL;
}
void krk_freeTable(KrkTable * table) {
FREE_ARRAY(KrkTableEntry, table->entries, table->capacity);
KRK_FREE_ARRAY(KrkTableEntry, table->entries, table->capacity);
KRK_FREE_ARRAY(ssize_t, table->indexes, table->capacity);
krk_initTable(table);
}
@ -38,8 +60,12 @@ inline int krk_hashValue(KrkValue value, uint32_t *hashOut) {
}
break;
default:
#ifndef KRK_NO_FLOAT
*hashOut = (uint32_t)AS_FLOATING(value);
return 0;
#else
break;
#endif
}
KrkClass * type = krk_getType(value);
if (type && type->_hash) {
@ -50,7 +76,7 @@ inline int krk_hashValue(KrkValue value, uint32_t *hashOut) {
return 0;
}
if (IS_CLASS(value)) {
*hashOut = INTEGER_VAL((int)(intptr_t)AS_OBJECT(value));
*hashOut = (uint32_t)((int)(intptr_t)AS_OBJECT(value));
return 0;
}
_unhashable:
@ -59,106 +85,117 @@ _unhashable:
return 1;
}
KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue key) {
static inline ssize_t krk_tableIndexKeyC(const KrkTableEntry * entries, const ssize_t * indexes, size_t capacity, KrkValue key, int (*comparator)(KrkValue,KrkValue)) {
uint32_t index;
if (krk_hashValue(key, &index)) {
return NULL;
}
index &= (capacity-1);
KrkTableEntry * tombstone = NULL;
if (krk_hashValue(key, &index)) return -1;
index &= (capacity - 1);
ssize_t tombstone = -1;
for (;;) {
KrkTableEntry * entry = &entries[index];
if (entry->key == KWARGS_VAL(0)) {
return tombstone != NULL ? tombstone : entry;
} else if (entry->key == KWARGS_VAL(1)) {
if (tombstone == entry) return tombstone;
if (tombstone == NULL) tombstone = entry;
} else if (krk_valuesSameOrEqual(entry->key, key)) {
return entry;
if (indexes[index] == -1) {
return tombstone != -1 ? tombstone : index;
} else if (indexes[index] == -2) {
if (tombstone == index) return tombstone;
if (tombstone == -1) tombstone = index;
} else if (comparator(entries[indexes[index]].key, key)) {
return index;
}
index = (index + 1) & (capacity-1);
index = (index + 1) & (capacity - 1);
}
}
KrkTableEntry * krk_findEntryExact(KrkTableEntry * entries, size_t capacity, KrkValue key) {
uint32_t index;
if (krk_hashValue(key, &index)) {
return NULL;
}
index &= (capacity-1);
KrkTableEntry * tombstone = NULL;
for (;;) {
KrkTableEntry * entry = &entries[index];
if (entry->key == KWARGS_VAL(0)) {
return tombstone != NULL ? tombstone : entry;
} else if (entry->key == KWARGS_VAL(1)) {
if (tombstone == entry) return tombstone;
if (tombstone == NULL) tombstone = entry;
} else if (krk_valuesSame(entry->key, key)) {
return entry;
}
index = (index + 1) & (capacity-1);
}
static ssize_t krk_tableIndexKey(const KrkTableEntry * entries, const ssize_t * indexes, size_t capacity, KrkValue key) {
return krk_tableIndexKeyC(entries,indexes,capacity,key,krk_valuesSameOrEqual);
}
#ifdef __TINYC__
int __builtin_clz(unsigned int x) {
int i = 31;
while (!(x & (1 << i)) && i >= 0) i--;
return 31-i;
static ssize_t krk_tableIndexKeyExact(const KrkTableEntry * entries, const ssize_t * indexes, size_t capacity, KrkValue key) {
return krk_tableIndexKeyC(entries,indexes,capacity,key,krk_valuesSame);
}
#endif
void krk_tableAdjustCapacity(KrkTable * table, size_t capacity) {
if (capacity) {
/* Fast power-of-two calculation */
size_t powerOfTwoCapacity = __builtin_clz(1) - __builtin_clz(capacity);
if ((1UL << powerOfTwoCapacity) != capacity) powerOfTwoCapacity++;
capacity = (1UL << powerOfTwoCapacity);
}
KrkTableEntry * entries = ALLOCATE(KrkTableEntry, capacity);
KrkTableEntry * nentries = KRK_ALLOCATE(KrkTableEntry, capacity);
ssize_t * nindexes = KRK_ALLOCATE(ssize_t, capacity);
for (size_t i = 0; i < capacity; ++i) {
entries[i].key = KWARGS_VAL(0);
entries[i].value = KWARGS_VAL(0);
nindexes[i] = -1;
nentries[i].key = KWARGS_VAL(0);
nentries[i].value = KWARGS_VAL(0);
}
table->count = 0;
for (size_t i = 0; i < table->capacity; ++i) {
KrkTableEntry * entry = &table->entries[i];
if (IS_KWARGS(entry->key)) continue;
KrkTableEntry * dest = krk_findEntry(entries, capacity, entry->key);
dest->key = entry->key;
dest->value = entry->value;
table->count++;
/* Fill in used entries */
const KrkTableEntry * e = table->entries;
for (size_t i = 0; i < table->count; ++i) {
while (IS_KWARGS(e->key)) e++;
memcpy(&nentries[i], e, sizeof(KrkTableEntry));
ssize_t indexkey = krk_tableIndexKeyExact(nentries,nindexes,capacity, e->key);
nindexes[indexkey] = i;
e++;
}
FREE_ARRAY(KrkTableEntry, table->entries, table->capacity);
table->entries = entries;
/* Swap before freeing */
KrkTableEntry * oldEntries = table->entries;
table->entries = nentries;
KRK_FREE_ARRAY(KrkTableEntry, oldEntries, table->capacity);
ssize_t * oldIndexes = table->indexes;
table->indexes = nindexes;
KRK_FREE_ARRAY(ssize_t, oldIndexes, table->capacity);
/* Update table with new capacity and used count */
table->capacity = capacity;
table->used = table->count;
}
int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) {
if (table->count + 1 > table->capacity * TABLE_MAX_LOAD) {
size_t capacity = GROW_CAPACITY(table->capacity);
if (table->used + 1 > table->capacity * TABLE_MAX_LOAD) {
size_t capacity = KRK_GROW_CAPACITY(table->capacity);
krk_tableAdjustCapacity(table, capacity);
}
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
if (!entry) return 0;
int isNewKey = IS_KWARGS(entry->key);
if (isNewKey) table->count++;
entry->key = key;
ssize_t index = krk_tableIndexKey(table->entries, table->indexes, table->capacity, key);
if (index < 0) return 0;
KrkTableEntry * entry;
int isNew = table->indexes[index] < 0;
if (isNew) {
table->indexes[index] = table->used;
entry = &table->entries[table->used];
entry->key = key;
table->used++;
table->count++;
} else {
entry = &table->entries[table->indexes[index]];
}
entry->value = value;
return isNewKey;
return isNew;
}
int krk_tableSetExact(KrkTable * table, KrkValue key, KrkValue value) {
if (table->used + 1 > table->capacity * TABLE_MAX_LOAD) {
size_t capacity = KRK_GROW_CAPACITY(table->capacity);
krk_tableAdjustCapacity(table, capacity);
}
ssize_t index = krk_tableIndexKeyExact(table->entries, table->indexes, table->capacity, key);
if (index < 0) return 0;
KrkTableEntry * entry;
int isNew = table->indexes[index] < 0;
if (isNew) {
table->indexes[index] = table->used;
entry = &table->entries[table->used];
entry->key = key;
table->used++;
table->count++;
} else {
entry = &table->entries[table->indexes[index]];
}
entry->value = value;
return isNew;
}
int krk_tableSetIfExists(KrkTable * table, KrkValue key, KrkValue value) {
if (table->count == 0) return 0;
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
if (!entry) return 0;
if (IS_KWARGS(entry->key)) return 0; /* Not found */
entry->key = key;
entry->value = value;
ssize_t index = krk_tableIndexKey(table->entries, table->indexes, table->capacity, key);
if (index < 0 || table->indexes[index] < 0) return 0;
table->entries[table->indexes[index]].value = value;
return 1;
}
@ -173,75 +210,69 @@ void krk_tableAddAll(KrkTable * from, KrkTable * to) {
int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) {
if (table->count == 0) return 0;
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
if (!entry || IS_KWARGS(entry->key)) {
return 0;
} else {
*value = entry->value;
return 1;
}
ssize_t index = krk_tableIndexKey(table->entries, table->indexes, table->capacity, key);
if (index < 0 || table->indexes[index] < 0) return 0;
*value = table->entries[table->indexes[index]].value;
return 1;
}
int krk_tableGet_fast(KrkTable * table, KrkString * str, KrkValue * value) {
if (unlikely(table->count == 0)) return 0;
if (table->count == 0) return 0;
uint32_t index = str->obj.hash & (table->capacity-1);
KrkTableEntry * tombstone = NULL;
ssize_t tombstone = -1;
for (;;) {
KrkTableEntry * entry = &table->entries[index];
if (entry->key == KWARGS_VAL(0)) {
if (table->indexes[index] == -1) {
return 0;
} else if (entry->key == KWARGS_VAL(1)) {
if (tombstone == entry) return 0;
if (tombstone == NULL) tombstone = entry;
} else if (entry->key == OBJECT_VAL(str)) {
*value = entry->value;
} else if (table->indexes[index] == -2) {
if (tombstone == index) return 0;
if (tombstone == -1) tombstone = index;
} else if (krk_valuesSame(table->entries[table->indexes[index]].key, OBJECT_VAL(str))) {
*value = table->entries[table->indexes[index]].value;
return 1;
}
index = (index + 1) & (table->capacity-1);
index = (index + 1) & (table->capacity - 1);
}
}
int krk_tableDelete(KrkTable * table, KrkValue key) {
if (table->count == 0) return 0;
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
if (!entry || IS_KWARGS(entry->key)) {
return 0;
}
ssize_t index = krk_tableIndexKey(table->entries, table->indexes, table->capacity, key);
if (index < 0 || table->indexes[index] < 0) return 0;
table->count--;
entry->key = KWARGS_VAL(1);
entry->value = KWARGS_VAL(0);
table->entries[table->indexes[index]].key = KWARGS_VAL(0);
table->entries[table->indexes[index]].value = KWARGS_VAL(0);
table->indexes[index] = -2;
return 1;
}
int krk_tableDeleteExact(KrkTable * table, KrkValue key) {
if (table->count == 0) return 0;
KrkTableEntry * entry = krk_findEntryExact(table->entries, table->capacity, key);
if (!entry || IS_KWARGS(entry->key)) {
return 0;
}
ssize_t index = krk_tableIndexKeyExact(table->entries, table->indexes, table->capacity, key);
if (index < 0 || table->indexes[index] < 0) return 0;
table->count--;
entry->key = KWARGS_VAL(1);
entry->value = KWARGS_VAL(0);
table->entries[table->indexes[index]].key = KWARGS_VAL(0);
table->entries[table->indexes[index]].value = KWARGS_VAL(0);
table->indexes[index] = -2;
return 1;
}
KrkString * krk_tableFindString(KrkTable * table, const char * chars, size_t length, uint32_t hash) {
if (table->count == 0) return NULL;
uint32_t index = hash & (table->capacity - 1);
uint32_t index = hash & (table->capacity-1);
KrkTableEntry * tombstone = NULL;
ssize_t tombstone = -1;
for (;;) {
KrkTableEntry * entry = &table->entries[index];
if (entry->key == KWARGS_VAL(0)) {
if (table->indexes[index] == -1) {
return NULL;
} else if (entry->key == KWARGS_VAL(1)) {
if (tombstone == entry) return NULL;
if (tombstone == NULL) tombstone = entry;
} else if (AS_STRING(entry->key)->length == length &&
AS_OBJECT(entry->key)->hash == hash &&
memcmp(AS_STRING(entry->key)->chars, chars, length) == 0) {
return AS_STRING(entry->key);
} else if (table->indexes[index] == -2) {
if (tombstone == index) return NULL;
if (tombstone == -1) tombstone = index;
} else if (AS_STRING(table->entries[table->indexes[index]].key)->length == length &&
AS_OBJECT(table->entries[table->indexes[index]].key)->hash == hash &&
memcmp(AS_STRING(table->entries[table->indexes[index]].key)->chars, chars, length) == 0) {
return AS_STRING(table->entries[table->indexes[index]].key);
}
index = (index + 1) & (table->capacity-1);
index = (index + 1) & (table->capacity - 1);
}
}

View File

@ -4,6 +4,7 @@
#ifndef KRK_DISABLE_THREADS
#include <kuroko/util.h>
#include <kuroko/threads.h>
#include <unistd.h>
#include <pthread.h>
@ -36,6 +37,7 @@ struct Thread {
pid_t tid;
unsigned int started:1;
unsigned int alive:1;
unsigned int maxrec;
};
/**
@ -61,11 +63,13 @@ KRK_Function(current_thread) {
static volatile int _threadLock = 0;
static void * _startthread(void * _threadObj) {
struct Thread * self = _threadObj;
#if defined(__APPLE__) && defined(__aarch64__)
krk_forceThreadData();
#endif
memset(&krk_currentThread, 0, sizeof(KrkThreadState));
krk_currentThread.frames = calloc(vm.maximumCallDepth,sizeof(KrkCallFrame));
krk_currentThread.maximumCallDepth = self->maxrec;
krk_currentThread.frames = calloc(krk_currentThread.maximumCallDepth,sizeof(KrkCallFrame));
vm.globalFlags |= KRK_GLOBAL_THREADS;
_obtain_lock(_threadLock);
if (vm.threads->next) {
@ -75,7 +79,6 @@ static void * _startthread(void * _threadObj) {
_release_lock(_threadLock);
/* Get our run function */
struct Thread * self = _threadObj;
self->threadState = &krk_currentThread;
self->tid = gettid();
@ -104,7 +107,7 @@ static void * _startthread(void * _threadObj) {
}
_release_lock(_threadLock);
FREE_ARRAY(size_t, krk_currentThread.stack, krk_currentThread.stackSize);
KRK_FREE_ARRAY(size_t, krk_currentThread.stack, krk_currentThread.stackSize);
free(krk_currentThread.frames);
return NULL;
@ -126,13 +129,15 @@ KRK_Method(Thread,join) {
}
KRK_Method(Thread,start) {
METHOD_TAKES_NONE();
unsigned int maxrec = krk_currentThread.maximumCallDepth;
if (!krk_parseArgs(".|I", (const char*[]){"maxrec"}, &maxrec)) return NONE_VAL();
if (self->started)
return krk_runtimeError(KRK_EXC(ThreadError), "Thread has already been started.");
self->started = 1;
self->alive = 1;
self->maxrec = maxrec;
pthread_create(&self->nativeRef, NULL, _startthread, (void*)self);
return argv[0];
@ -152,7 +157,7 @@ KRK_Method(Thread,is_alive) {
KRK_Method(Lock,__init__) {
METHOD_TAKES_NONE(); /* TODO lock options, like recursive or error-checked? */
pthread_mutex_init(&self->mutex, NULL);
return argv[0];
return NONE_VAL();
}
static inline void _pushLockStatus(struct Lock * self, struct StringBuilder * sb) {

View File

@ -1,56 +0,0 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <kuroko/vm.h>
#include <kuroko/value.h>
#include <kuroko/object.h>
#include <kuroko/util.h>
KRK_Function(sleep) {
FUNCTION_TAKES_EXACTLY(1);
if (!IS_INTEGER(argv[0]) && !IS_FLOATING(argv[0])) {
return TYPE_ERROR(int or float,argv[0]);
}
unsigned int usecs = (IS_INTEGER(argv[0]) ? AS_INTEGER(argv[0]) :
(IS_FLOATING(argv[0]) ? AS_FLOATING(argv[0]) : 0)) *
1000000;
usleep(usecs);
return BOOLEAN_VAL(1);
}
KRK_Function(time) {
FUNCTION_TAKES_NONE();
struct timeval tv;
gettimeofday(&tv,NULL);
double out = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
return FLOATING_VAL(out);
}
void krk_module_init_time(void) {
KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "time", (KrkObj*)module);
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("time"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
KRK_DOC(module, "@brief Provides timekeeping functions.");
KRK_DOC(BIND_FUNC(module,sleep), "@brief Pause execution of the current thread.\n"
"@arguments secs\n\n"
"Uses the system @c usleep() function to sleep for @p secs seconds, which may be a @ref float or @ref int. "
"The available precision is platform-dependent.");
KRK_DOC(BIND_FUNC(module,time), "@brief Return the elapsed seconds since the system epoch.\n\n"
"Returns a @ref float representation of the number of seconds since the platform's epoch date. "
"On POSIX platforms, this is the number of seconds since 1 January 1970. "
"The precision of the return value is platform-dependent.");
}

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 = GROW_CAPACITY(old);
array->values = GROW_ARRAY(KrkValue, array->values, old, array->capacity);
array->capacity = KRK_GROW_CAPACITY(old);
array->values = KRK_GROW_ARRAY(KrkValue, array->values, old, array->capacity);
}
array->values[array->count] = value;
@ -26,129 +26,10 @@ void krk_writeValueArray(KrkValueArray * array, KrkValue value) {
}
void krk_freeValueArray(KrkValueArray * array) {
FREE_ARRAY(KrkValue, array->values, array->capacity);
KRK_FREE_ARRAY(KrkValue, array->values, array->capacity);
krk_initValueArray(array);
}
void krk_printValue(FILE * f, KrkValue printable) {
KrkClass * type = krk_getType(printable);
if (type->_tostr) {
krk_push(printable);
printable = krk_callDirect(type->_tostr, 1);
if (!IS_STRING(printable)) return;
fprintf(f, "%s", AS_CSTRING(printable));
} else if (type->_reprer) {
krk_push(printable);
printable = krk_callDirect(type->_reprer, 1);
if (!IS_STRING(printable)) return;
fprintf(f, "%s", AS_CSTRING(printable));
} else {
fprintf(f, "%s", krk_typeName(printable));
}
}
#define STRING_DEBUG_TRUNCATE 50
void krk_printValueSafe(FILE * f, KrkValue printable) {
if (!IS_OBJECT(printable)) {
switch (KRK_VAL_TYPE(printable)) {
case KRK_VAL_INTEGER: fprintf(f, PRIkrk_int, AS_INTEGER(printable)); break;
case KRK_VAL_BOOLEAN: fprintf(f, "%s", AS_BOOLEAN(printable) ? "True" : "False"); break;
case KRK_VAL_NONE: fprintf(f, "None"); break;
case KRK_VAL_HANDLER:
switch (AS_HANDLER_TYPE(printable)) {
case OP_PUSH_TRY: fprintf(f, "{try->%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_PUSH_WITH: fprintf(f, "{with->%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_RAISE: fprintf(f, "{raise<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_FILTER_EXCEPT: fprintf(f, "{except<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_BEGIN_FINALLY: fprintf(f, "{finally<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_RETURN: fprintf(f, "{return<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_END_FINALLY: fprintf(f, "{end<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
case OP_EXIT_LOOP: fprintf(f, "{exit<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
}
break;
case KRK_VAL_KWARGS: {
if (AS_INTEGER(printable) == KWARGS_SINGLE) {
fprintf(f, "{unpack single}");
} else if (AS_INTEGER(printable) == KWARGS_LIST) {
fprintf(f, "{unpack list}");
} else if (AS_INTEGER(printable) == KWARGS_DICT) {
fprintf(f, "{unpack dict}");
} else if (AS_INTEGER(printable) == KWARGS_NIL) {
fprintf(f, "{unpack nil}");
} else if (AS_INTEGER(printable) == KWARGS_UNSET) {
fprintf(f, "{unset default}");
} else {
fprintf(f, "{sentinel=" PRIkrk_int "}",AS_INTEGER(printable));
}
break;
}
default:
if (IS_FLOATING(printable)) fprintf(f, "%.16g", AS_FLOATING(printable));
break;
}
} else if (IS_STRING(printable)) {
fprintf(f, "'");
/*
* Print at most STRING_DEBUG_TRUNCATE characters, as bytes, escaping anything not ASCII.
* See also str.__repr__ which does something similar with escape sequences, but this
* is a dumber, safer, and slightly faster approach.
*/
for (size_t c = 0; c < AS_STRING(printable)->length && c < STRING_DEBUG_TRUNCATE; ++c) {
unsigned char byte = (unsigned char)AS_CSTRING(printable)[c];
switch (byte) {
case '\\': fprintf(f, "\\\\"); break;
case '\n': fprintf(f, "\\n"); break;
case '\r': fprintf(f, "\\r"); break;
case '\'': fprintf(f, "\\'"); break;
default: {
if (byte < ' ' || byte > '~') {
fprintf(f, "\\x%02x", byte);
} else {
fprintf(f, "%c", byte);
}
break;
}
}
}
if (AS_STRING(printable)->length > STRING_DEBUG_TRUNCATE) {
fprintf(f,"...");
}
fprintf(f,"'");
} else {
switch (AS_OBJECT(printable)->type) {
case KRK_OBJ_CODEOBJECT: fprintf(f, "<codeobject %s>", AS_codeobject(printable)->name ? AS_codeobject(printable)->name->chars : "?"); break;
case KRK_OBJ_CLASS: fprintf(f, "<class %s>", AS_CLASS(printable)->name ? AS_CLASS(printable)->name->chars : "?"); break;
case KRK_OBJ_INSTANCE: fprintf(f, "<instance of %s>", AS_INSTANCE(printable)->_class->name->chars); break;
case KRK_OBJ_NATIVE: fprintf(f, "<nativefn %s>", ((KrkNative*)AS_OBJECT(printable))->name); break;
case KRK_OBJ_CLOSURE: fprintf(f, "<function %s>", AS_CLOSURE(printable)->function->name->chars); break;
case KRK_OBJ_BYTES: fprintf(f, "<bytes of len %ld>", (long)AS_BYTES(printable)->length); break;
case KRK_OBJ_TUPLE: {
fprintf(f, "(");
for (size_t i = 0; i < AS_TUPLE(printable)->values.count; ++i) {
krk_printValueSafe(f, AS_TUPLE(printable)->values.values[i]);
if (i + 1 != AS_TUPLE(printable)->values.count) {
fprintf(f, ",");
}
}
fprintf(f, ")");
} break;
case KRK_OBJ_BOUND_METHOD: fprintf(f, "<method %s>",
AS_BOUND_METHOD(printable)->method ? (
AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_CLOSURE ? ((KrkClosure*)AS_BOUND_METHOD(printable)->method)->function->name->chars :
(AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_NATIVE ? ((KrkNative*)AS_BOUND_METHOD(printable)->method)->name : "(unknown)")) : "(corrupt bound method)"); break;
default: fprintf(f, "<%s>", krk_typeName(printable)); break;
}
}
}
/**
* Identity really should be the simple...
*/
int krk_valuesSame(KrkValue a, KrkValue b) {
return a == b;
}
static inline int _krk_method_equivalence(KrkValue a, KrkValue b) {
KrkClass * type = krk_getType(a);
if (likely(type && type->_eq)) {
@ -181,7 +62,7 @@ static inline int _krk_same_type_equivalence(uint16_t valtype, KrkValue a, KrkVa
case KRK_VAL_NOTIMPL:
case KRK_VAL_KWARGS:
case KRK_VAL_HANDLER:
return a == b;
return krk_valuesSame(a,b);
case KRK_VAL_OBJECT:
default:
return _krk_method_equivalence(a,b);
@ -211,9 +92,9 @@ static inline int _krk_diff_type_equivalence(uint16_t val_a, uint16_t val_b, Krk
return _krk_method_equivalence(a,b);
}
__attribute__((hot))
_hot
int krk_valuesSameOrEqual(KrkValue a, KrkValue b) {
if (a == b) return 1;
if (krk_valuesSame(a,b)) return 1;
uint16_t val_a = KRK_VAL_TYPE(a);
uint16_t val_b = KRK_VAL_TYPE(b);
return (val_a == val_b)
@ -221,7 +102,7 @@ int krk_valuesSameOrEqual(KrkValue a, KrkValue b) {
: _krk_diff_type_equivalence(val_a, val_b, a, b);
}
__attribute__((hot))
_hot
int krk_valuesEqual(KrkValue a, KrkValue b) {
uint16_t val_a = KRK_VAL_TYPE(a);
uint16_t val_b = KRK_VAL_TYPE(b);

55
src/vendor/rline.c vendored
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 = "@5";
static const char * COLOR_ALT_FG = "@9";
static const char * COLOR_ALT_BG = "@9";
static const char * COLOR_KEYWORD = "@4";
static const char * COLOR_STRING = "@2";
static const char * COLOR_COMMENT = "@5";
static const char * COLOR_TYPE = "@3";
static const char * COLOR_PRAGMA = "@1";
static const char * COLOR_NUMERAL = "@1";
static const char * COLOR_RED = "@1";
static const char * COLOR_GREEN = "@2";
static const char * COLOR_ESCAPE = "@2";
static const char * COLOR_SEARCH_FG = "@0";
static const char * COLOR_SEARCH_BG = "@3";
static const char * COLOR_KEYWORD = "@9";
static const char * COLOR_STRING = "@9";
static const char * COLOR_COMMENT = "@9";
static const char * COLOR_TYPE = "@9";
static const char * COLOR_PRAGMA = "@9";
static const char * COLOR_NUMERAL = "@9";
static const char * COLOR_RED = "@9";
static const char * COLOR_GREEN = "@9";
static const char * COLOR_ESCAPE = "@9";
static const char * COLOR_SEARCH_FG = "@9";
static const char * COLOR_SEARCH_BG = "@9";
static const char * COLOR_ERROR_FG = "@9";
static const char * COLOR_ERROR_BG = "@9";
static const char * COLOR_BOLD = "@9";
@ -560,7 +560,7 @@ static char * syn_krk_types[] = {
"self", "super", /* implicit in a class method */
"len", "str", "int", "float", "dir", "repr", /* global functions from __builtins__ */
"list","dict","range", /* builtin classes */
"object","exception","isinstance","type","tuple","reversed",
"object","isinstance","type","tuple","reversed",
"print","set","any","all","bool","ord","chr","hex","oct","filter",
"sorted","bytes","getattr","sum","min","max","id","hash","map","bin",
"enumerate","zip","setattr","property","staticmethod","classmethod",
@ -672,6 +672,11 @@ static int paint_krk_numeral(struct syntax_state * state) {
paint(1, FLAG_NUMERAL);
while (isdigit(charat())) paint(1, FLAG_NUMERAL);
}
if (charat() == 'e' || charat() == 'E') {
paint(1, FLAG_NUMERAL);
if (charat() == '-' || charat() == '+') paint(1, FLAG_NUMERAL);
while (isdigit(charat())) paint(1, FLAG_NUMERAL);
}
}
return 0;
}
@ -2011,29 +2016,27 @@ static int handle_escape(int * this_buf, int * timeout, int c) {
#ifndef _WIN32
static unsigned int _INTR, _EOF;
static struct termios old;
static void get_initial_termios(void) {
static void set_unbuffered(void) {
tcgetattr(STDOUT_FILENO, &old);
_INTR = old.c_cc[VINTR];
_EOF = old.c_cc[VEOF];
}
static void set_unbuffered(void) {
struct termios new = old;
new.c_lflag &= (~ICANON & ~ECHO & ~ISIG);
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &new);
tcsetattr(STDOUT_FILENO, TCSADRAIN, &new);
if (wcwidth(0x3042) != 2) setlocale(LC_CTYPE, "");
}
static void set_buffered(void) {
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &old);
tcsetattr(STDOUT_FILENO, TCSADRAIN, &old);
}
#else
static unsigned int _INTR = 3;
static unsigned int _EOF = 4;
static void get_initial_termios(void) {
}
static void set_unbuffered(void) {
/* Disables line input, echo, ^C processing, and a few others. */
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_VIRTUAL_TERMINAL_INPUT);
SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_WRAP_AT_EOL_OUTPUT);
setlocale(LC_CTYPE, "C.UTF-8");
}
static void set_buffered(void) {
/* These are the defaults */
@ -2429,12 +2432,6 @@ static int read_line(void) {
* Read a line of text with interactive editing.
*/
int rline(char * buffer, int buf_size) {
#ifndef _WIN32
setlocale(LC_ALL, "");
#else
setlocale(LC_ALL, "C.UTF-8");
#endif
get_initial_termios();
set_unbuffered();
get_size();
@ -2442,8 +2439,12 @@ int rline(char * buffer, int buf_size) {
offset = 0;
buf_size_max = buf_size;
char * noColor = getenv("NO_COLOR");
char * theme = getenv("RLINE_THEME");
if (theme && !strcmp(theme,"sunsmoke")) { /* TODO bring back theme tables */
if ((noColor && *noColor) || (theme && !strcmp(theme,"none"))) {
/* If NO_COLOR is set, or RLINE_THEME=none, set no theme.
* The default colors are all @9. */
} else if (theme && !strcmp(theme,"sunsmoke")) {
rline_exp_load_colorscheme_sunsmoke();
} else {
rline_exp_load_colorscheme_default();

709
src/vm.c

File diff suppressed because it is too large Load Diff

View File

@ -1,389 +1,389 @@
Checking {'hcl': '#602927', 'iyr': '2019', 'hgt': '186cm', 'byr': '1939', 'pid': '552194973', 'eyr': '2027', 'ecl': 'hzl'}
Checking {'hcl': '#866857', 'iyr': '2015', 'hgt': '164cm', 'pid': '657988073', 'byr': '1996', 'eyr': '2020', 'ecl': 'brn'}
Checking {'eyr': '2022', 'hcl': '#fffffd', 'iyr': '2017', 'hgt': '62in', 'byr': '1951', 'pid': '#6ef4e1', 'ecl': 'brn', 'cid': '321'}
Checking {'eyr': '2027', 'hcl': '#602927', 'hgt': '186cm', 'byr': '1939', 'iyr': '2019', 'pid': '552194973', 'ecl': 'hzl'}
Checking {'pid': '657988073', 'eyr': '2020', 'byr': '1996', 'ecl': 'brn', 'hcl': '#866857', 'iyr': '2015', 'hgt': '164cm'}
Checking {'hcl': '#fffffd', 'byr': '1951', 'cid': '321', 'iyr': '2017', 'eyr': '2022', 'ecl': 'brn', 'hgt': '62in', 'pid': '#6ef4e1'}
bad pid
Checking {'ecl': 'brn', 'hcl': '#fffffd', 'iyr': '2011', 'hgt': '150cm', 'byr': '1980', 'pid': '420023864', 'eyr': '2025', 'cid': '129'}
Checking {'hcl': '#ceb3a1', 'iyr': '2016', 'hgt': '187cm', 'byr': '1925', 'pid': '223151011', 'eyr': '2029', 'ecl': 'amb'}
Checking {'hcl': '#cfa07d', 'iyr': '2010', 'hgt': '190cm', 'pid': '135392110', 'byr': '1959', 'ecl': 'brn', 'eyr': '2022'}
Checking {'ecl': 'grn', 'hcl': '#a97842', 'iyr': '2018', 'pid': '522856696', 'byr': '1961', 'eyr': '2024', 'cid': '225'}
Checking {'eyr': '2025', 'iyr': '2011', 'byr': '1980', 'hcl': '#fffffd', 'cid': '129', 'pid': '420023864', 'hgt': '150cm', 'ecl': 'brn'}
Checking {'eyr': '2029', 'hcl': '#ceb3a1', 'hgt': '187cm', 'byr': '1925', 'ecl': 'amb', 'pid': '223151011', 'iyr': '2016'}
Checking {'hcl': '#cfa07d', 'ecl': 'brn', 'eyr': '2022', 'pid': '135392110', 'iyr': '2010', 'hgt': '190cm', 'byr': '1959'}
Checking {'eyr': '2024', 'cid': '225', 'iyr': '2018', 'pid': '522856696', 'byr': '1961', 'hcl': '#a97842', 'ecl': 'grn'}
Missing expected value
Checking {'hcl': '#866857', 'iyr': '1976', 'hgt': '190cm', 'byr': '1964', 'pid': '562135232', 'eyr': '2024', 'ecl': 'brn'}
Checking {'eyr': '2024', 'byr': '1964', 'ecl': 'brn', 'iyr': '1976', 'hcl': '#866857', 'hgt': '190cm', 'pid': '562135232'}
Bad issue year
Checking {'eyr': '2022', 'hcl': 'z', 'iyr': '2011', 'hgt': '193cm', 'pid': '#6e4342', 'byr': '1936', 'cid': '296', 'ecl': '#3b8ed3'}
Checking {'hgt': '193cm', 'pid': '#6e4342', 'iyr': '2011', 'byr': '1936', 'cid': '296', 'hcl': 'z', 'ecl': '#3b8ed3', 'eyr': '2022'}
bad hair color
Checking {'ecl': 'gry', 'hcl': '#efcc98', 'iyr': '2014', 'byr': '1985', 'pid': '503255860', 'eyr': '2023', 'cid': '154'}
Checking {'cid': '154', 'byr': '1985', 'pid': '503255860', 'ecl': 'gry', 'eyr': '2023', 'hcl': '#efcc98', 'iyr': '2014'}
Missing expected value
Checking {'hcl': '#341e13', 'iyr': '2012', 'hgt': '154cm', 'pid': '631051435', 'byr': '1986', 'eyr': '2026', 'ecl': 'amb'}
Checking {'eyr': '2035', 'hcl': '#623a2f', 'iyr': '2019', 'hgt': '155cm', 'pid': '318048681', 'byr': '1984', 'cid': '179', 'ecl': 'brn'}
Checking {'eyr': '2026', 'iyr': '2012', 'pid': '631051435', 'byr': '1986', 'ecl': 'amb', 'hgt': '154cm', 'hcl': '#341e13'}
Checking {'hcl': '#623a2f', 'pid': '318048681', 'ecl': 'brn', 'eyr': '2035', 'hgt': '155cm', 'cid': '179', 'byr': '1984', 'iyr': '2019'}
Bad expire year
Checking {'hcl': '#733820', 'iyr': '2013', 'hgt': '189cm', 'byr': '1969', 'pid': '185953891', 'eyr': '2024', 'ecl': 'amb'}
Checking {'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '61cm', 'byr': '2012', 'pid': '33668114', 'ecl': '#38f2a6', 'eyr': '2021'}
Checking {'iyr': '2013', 'hcl': '#733820', 'eyr': '2024', 'hgt': '189cm', 'ecl': 'amb', 'byr': '1969', 'pid': '185953891'}
Checking {'hcl': '#cfa07d', 'ecl': '#38f2a6', 'iyr': '2013', 'hgt': '61cm', 'eyr': '2021', 'byr': '2012', 'pid': '33668114'}
Bad birth year
Checking {'cid': '51', 'hcl': '4946ca', 'iyr': '2019', 'hgt': '189', 'pid': '47030948', 'byr': '2013', 'ecl': '#1d136d', 'eyr': '2024'}
Checking {'pid': '47030948', 'hcl': '4946ca', 'iyr': '2019', 'hgt': '189', 'ecl': '#1d136d', 'byr': '2013', 'eyr': '2024', 'cid': '51'}
Bad birth year
Checking {'eyr': '2020', 'hcl': '#c0946f', 'iyr': '2011', 'hgt': '162cm', 'byr': '1935', 'pid': '883047970', 'ecl': 'grn', 'cid': '51'}
Checking {'cid': '221', 'hcl': '#623a2f', 'iyr': '2018', 'hgt': '155cm', 'pid': '013760919', 'byr': '1942', 'ecl': 'blu', 'eyr': '2020'}
Checking {'hcl': '#7d3b0c', 'iyr': '1986', 'hgt': '152cm', 'pid': '29797863', 'byr': '2000', 'eyr': '2030', 'ecl': 'amb'}
Checking {'ecl': 'grn', 'iyr': '2011', 'hgt': '162cm', 'byr': '1935', 'hcl': '#c0946f', 'pid': '883047970', 'cid': '51', 'eyr': '2020'}
Checking {'pid': '013760919', 'iyr': '2018', 'byr': '1942', 'ecl': 'blu', 'hcl': '#623a2f', 'eyr': '2020', 'cid': '221', 'hgt': '155cm'}
Checking {'hgt': '152cm', 'eyr': '2030', 'ecl': 'amb', 'iyr': '1986', 'hcl': '#7d3b0c', 'pid': '29797863', 'byr': '2000'}
Bad issue year
Checking {'hcl': '#fffffd', 'iyr': '2013', 'hgt': '176cm', 'byr': '1995', 'pid': '546676799', 'ecl': 'brn', 'eyr': '2023'}
Checking {'iyr': '2015', 'byr': '1955', 'pid': '634493767', 'eyr': '2028', 'ecl': 'oth'}
Checking {'hgt': '176cm', 'byr': '1995', 'pid': '546676799', 'iyr': '2013', 'ecl': 'brn', 'hcl': '#fffffd', 'eyr': '2023'}
Checking {'byr': '1955', 'pid': '634493767', 'eyr': '2028', 'iyr': '2015', 'ecl': 'oth'}
Missing expected value
Checking {'ecl': 'oth', 'hcl': '#7d3b0c', 'iyr': '2020', 'hgt': '174cm', 'pid': '893757190', 'byr': '2002', 'cid': '150', 'eyr': '2027'}
Checking {'cid': '256', 'hcl': '#efcc98', 'iyr': '2012', 'hgt': '66in', 'pid': '790648045', 'byr': '1978', 'eyr': '2029', 'ecl': 'blu'}
Checking {'ecl': 'hzl', 'hcl': '#0eeb2d', 'iyr': '2020', 'hgt': '155cm', 'byr': '1945', 'pid': '048725571', 'cid': '209', 'eyr': '2027'}
Checking {'hcl': '#cfa07d', 'iyr': '2011', 'hgt': '162cm', 'byr': '2000', 'pid': '381372526', 'ecl': 'oth', 'eyr': '2023'}
Checking {'hcl': '#602927', 'iyr': '2018', 'hgt': '171cm', 'pid': '544462408', 'byr': '1994', 'ecl': 'blu', 'eyr': '2030'}
Checking {'eyr': '2025', 'hcl': '#733820', 'iyr': '2011', 'hgt': '187cm', 'pid': '533405863', 'byr': '1962', 'ecl': 'hzl', 'cid': '266'}
Checking {'hcl': '#b6652a', 'iyr': '2019', 'hgt': '155cm', 'byr': '1975', 'pid': '967013712', 'eyr': '2029', 'ecl': 'oth'}
Checking {'hcl': '#b6652a', 'iyr': '2010', 'hgt': '190cm', 'pid': '052112145', 'byr': '1982', 'eyr': '2022', 'ecl': 'amb'}
Checking {'hcl': '#b6652a', 'iyr': '2012', 'hgt': '183cm', 'byr': '1950', 'pid': '946714779', 'ecl': 'hzl', 'eyr': '2030'}
Checking {'cid': '103', 'hcl': '#ceb3a1', 'iyr': '2018', 'hgt': '70in', 'pid': '686010502', 'byr': '1993', 'ecl': 'gry', 'eyr': '2027'}
Checking {'hcl': '#733820', 'iyr': '2012', 'byr': '1976', 'hgt': '157cm', 'eyr': '2030', 'ecl': 'gry'}
Checking {'hcl': '#7d3b0c', 'iyr': '2020', 'cid': '150', 'hgt': '174cm', 'pid': '893757190', 'eyr': '2027', 'ecl': 'oth', 'byr': '2002'}
Checking {'eyr': '2029', 'pid': '790648045', 'byr': '1978', 'iyr': '2012', 'hcl': '#efcc98', 'ecl': 'blu', 'hgt': '66in', 'cid': '256'}
Checking {'iyr': '2020', 'byr': '1945', 'hgt': '155cm', 'cid': '209', 'eyr': '2027', 'hcl': '#0eeb2d', 'ecl': 'hzl', 'pid': '048725571'}
Checking {'hcl': '#cfa07d', 'byr': '2000', 'iyr': '2011', 'pid': '381372526', 'ecl': 'oth', 'eyr': '2023', 'hgt': '162cm'}
Checking {'ecl': 'blu', 'pid': '544462408', 'eyr': '2030', 'hgt': '171cm', 'iyr': '2018', 'hcl': '#602927', 'byr': '1994'}
Checking {'hcl': '#733820', 'iyr': '2011', 'hgt': '187cm', 'ecl': 'hzl', 'pid': '533405863', 'byr': '1962', 'cid': '266', 'eyr': '2025'}
Checking {'byr': '1975', 'hcl': '#b6652a', 'iyr': '2019', 'pid': '967013712', 'eyr': '2029', 'hgt': '155cm', 'ecl': 'oth'}
Checking {'iyr': '2010', 'eyr': '2022', 'ecl': 'amb', 'pid': '052112145', 'byr': '1982', 'hgt': '190cm', 'hcl': '#b6652a'}
Checking {'iyr': '2012', 'hgt': '183cm', 'hcl': '#b6652a', 'byr': '1950', 'ecl': 'hzl', 'pid': '946714779', 'eyr': '2030'}
Checking {'eyr': '2027', 'pid': '686010502', 'cid': '103', 'byr': '1993', 'hcl': '#ceb3a1', 'ecl': 'gry', 'hgt': '70in', 'iyr': '2018'}
Checking {'hcl': '#733820', 'iyr': '2012', 'hgt': '157cm', 'byr': '1976', 'eyr': '2030', 'ecl': 'gry'}
Missing expected value
Checking {'hcl': '#6b5442', 'iyr': '2017', 'hgt': '180cm', 'byr': '1955', 'pid': '732940101', 'ecl': 'hzl', 'eyr': '2022'}
Checking {'eyr': '2024', 'hcl': '#18171d', 'iyr': '2010', 'hgt': '188cm', 'byr': '1924', 'pid': '905274031', 'cid': '299', 'ecl': 'oth'}
Checking {'hcl': '#7f450a', 'iyr': '2013', 'hgt': '174cm', 'byr': '1999', 'pid': '021076124', 'eyr': '2024', 'ecl': 'gry'}
Checking {'hcl': '#866857', 'iyr': '2016', 'hgt': '176cm', 'byr': '1940', 'pid': '398320693', 'ecl': 'oth', 'eyr': '2026'}
Checking {'hcl': '#733820', 'iyr': '1931', 'pid': '158cm', 'hgt': '172cm', 'eyr': '2020', 'ecl': '#a0c290'}
Checking {'ecl': 'hzl', 'byr': '1955', 'hgt': '180cm', 'iyr': '2017', 'eyr': '2022', 'hcl': '#6b5442', 'pid': '732940101'}
Checking {'cid': '299', 'hgt': '188cm', 'byr': '1924', 'ecl': 'oth', 'pid': '905274031', 'iyr': '2010', 'eyr': '2024', 'hcl': '#18171d'}
Checking {'eyr': '2024', 'hgt': '174cm', 'byr': '1999', 'iyr': '2013', 'pid': '021076124', 'hcl': '#7f450a', 'ecl': 'gry'}
Checking {'hcl': '#866857', 'iyr': '2016', 'ecl': 'oth', 'hgt': '176cm', 'byr': '1940', 'pid': '398320693', 'eyr': '2026'}
Checking {'hgt': '172cm', 'eyr': '2020', 'hcl': '#733820', 'iyr': '1931', 'ecl': '#a0c290', 'pid': '158cm'}
Missing expected value
Checking {'hcl': '#341e13', 'iyr': '2018', 'hgt': '182cm', 'byr': '1990', 'pid': '444561212', 'ecl': 'blu', 'eyr': '2025'}
Checking {'hcl': '#602927', 'pid': '240732315', 'byr': '1976', 'hgt': '165cm', 'ecl': 'oth', 'eyr': '2023'}
Checking {'ecl': 'blu', 'iyr': '2018', 'eyr': '2025', 'hcl': '#341e13', 'byr': '1990', 'pid': '444561212', 'hgt': '182cm'}
Checking {'hcl': '#602927', 'hgt': '165cm', 'pid': '240732315', 'ecl': 'oth', 'eyr': '2023', 'byr': '1976'}
Missing expected value
Checking {'hcl': '#733820', 'iyr': '2016', 'hgt': '153cm', 'pid': '377612846', 'byr': '1967', 'ecl': 'brn', 'eyr': '2021'}
Checking {'cid': '114', 'hcl': '#733820', 'iyr': '2018', 'hgt': '187cm', 'byr': '1925', 'pid': '207103786', 'eyr': '2030', 'ecl': 'blu'}
Checking {'eyr': '2025', 'iyr': '2018', 'pid': '361909532', 'hgt': '184cm', 'ecl': 'blu', 'cid': '111'}
Checking {'iyr': '2016', 'ecl': 'brn', 'pid': '377612846', 'eyr': '2021', 'byr': '1967', 'hcl': '#733820', 'hgt': '153cm'}
Checking {'hgt': '187cm', 'iyr': '2018', 'eyr': '2030', 'ecl': 'blu', 'byr': '1925', 'hcl': '#733820', 'cid': '114', 'pid': '207103786'}
Checking {'hgt': '184cm', 'ecl': 'blu', 'cid': '111', 'iyr': '2018', 'pid': '361909532', 'eyr': '2025'}
Missing expected value
Checking {'hcl': '#7d3b0c', 'iyr': '2019', 'hgt': '184cm', 'byr': '1968', 'pid': '381103495', 'ecl': 'grn', 'eyr': '2026'}
Checking {'hcl': '#01adfd', 'iyr': '2019', 'byr': '1945', 'pid': '727826617', 'hgt': '151cm', 'eyr': '2020'}
Checking {'ecl': 'grn', 'byr': '1968', 'iyr': '2019', 'hgt': '184cm', 'pid': '381103495', 'hcl': '#7d3b0c', 'eyr': '2026'}
Checking {'iyr': '2019', 'byr': '1945', 'pid': '727826617', 'hcl': '#01adfd', 'eyr': '2020', 'hgt': '151cm'}
Missing expected value
Checking {'ecl': 'hzl', 'hcl': '#efcc98', 'iyr': '2011', 'hgt': '171cm', 'byr': '1924', 'pid': '235809608', 'eyr': '2029', 'cid': '280'}
Checking {'cid': '97', 'hcl': '#602927', 'iyr': '2010', 'hgt': '172cm', 'byr': '1973', 'pid': '599786261', 'eyr': '2029', 'ecl': 'gry'}
Checking {'hcl': '#866857', 'iyr': '2017', 'hgt': '163cm', 'pid': '768895320', 'byr': '1940', 'eyr': '2027', 'ecl': 'oth'}
Checking {'hcl': '#6b5442', 'iyr': '2013', 'byr': '1959', 'pid': '823221334', 'hgt': '178cm'}
Checking {'cid': '280', 'iyr': '2011', 'hcl': '#efcc98', 'ecl': 'hzl', 'eyr': '2029', 'byr': '1924', 'hgt': '171cm', 'pid': '235809608'}
Checking {'hcl': '#602927', 'byr': '1973', 'pid': '599786261', 'eyr': '2029', 'hgt': '172cm', 'iyr': '2010', 'ecl': 'gry', 'cid': '97'}
Checking {'iyr': '2017', 'eyr': '2027', 'pid': '768895320', 'hgt': '163cm', 'hcl': '#866857', 'byr': '1940', 'ecl': 'oth'}
Checking {'hgt': '178cm', 'hcl': '#6b5442', 'iyr': '2013', 'byr': '1959', 'pid': '823221334'}
Missing expected value
Checking {'eyr': '2024', 'hcl': '#da8af3', 'iyr': '2014', 'hgt': '150cm', 'pid': '534201972', 'byr': '1945', 'ecl': 'hzl', 'cid': '263'}
Checking {'cid': '341', 'hcl': '#efcc98', 'iyr': '2010', 'hgt': '189cm', 'pid': '469575516', 'byr': '1994', 'eyr': '2025', 'ecl': 'blu'}
Checking {'hcl': '#888785', 'iyr': '2015', 'hgt': '60in', 'byr': '1999', 'pid': '797138561', 'cid': '167', 'eyr': '2024'}
Checking {'iyr': '2014', 'pid': '534201972', 'ecl': 'hzl', 'hgt': '150cm', 'hcl': '#da8af3', 'byr': '1945', 'cid': '263', 'eyr': '2024'}
Checking {'pid': '469575516', 'hgt': '189cm', 'byr': '1994', 'eyr': '2025', 'iyr': '2010', 'ecl': 'blu', 'hcl': '#efcc98', 'cid': '341'}
Checking {'cid': '167', 'eyr': '2024', 'byr': '1999', 'pid': '797138561', 'hcl': '#888785', 'hgt': '60in', 'iyr': '2015'}
Missing expected value
Checking {'eyr': '2023', 'hcl': '#866857', 'iyr': '2014', 'hgt': '174cm', 'pid': '909549652', 'byr': '1967', 'cid': '103', 'ecl': 'amb'}
Checking {'eyr': '2027', 'iyr': '2016', 'hgt': '61in', 'pid': '813003671', 'byr': '1995', 'ecl': 'oth', 'cid': '95'}
Checking {'iyr': '2014', 'hcl': '#866857', 'cid': '103', 'pid': '909549652', 'byr': '1967', 'hgt': '174cm', 'ecl': 'amb', 'eyr': '2023'}
Checking {'pid': '813003671', 'ecl': 'oth', 'hgt': '61in', 'cid': '95', 'iyr': '2016', 'byr': '1995', 'eyr': '2027'}
Missing expected value
Checking {'hcl': '#fffffd', 'iyr': '2014', 'hgt': '166cm', 'pid': '000088706', 'byr': '1951', 'eyr': '2021', 'ecl': 'blu'}
Checking {'eyr': '2022', 'hcl': '#18171d', 'iyr': '2017', 'hgt': '162cm', 'byr': '1941', 'pid': '511728076', 'cid': '287', 'ecl': 'grn'}
Checking {'hcl': '#18171d', 'iyr': '2017', 'hgt': '191cm', 'pid': '209898040', 'byr': '1968', 'eyr': '2025', 'ecl': 'brn'}
Checking {'eyr': '2004', 'hcl': 'z', 'iyr': '2016', 'hgt': '190cm', 'byr': '1932', 'pid': '#02dfcc', 'cid': '201', 'ecl': '#6b9341'}
Checking {'eyr': '2021', 'hcl': '#fffffd', 'pid': '000088706', 'iyr': '2014', 'ecl': 'blu', 'hgt': '166cm', 'byr': '1951'}
Checking {'cid': '287', 'ecl': 'grn', 'byr': '1941', 'iyr': '2017', 'hcl': '#18171d', 'hgt': '162cm', 'pid': '511728076', 'eyr': '2022'}
Checking {'pid': '209898040', 'byr': '1968', 'eyr': '2025', 'hcl': '#18171d', 'ecl': 'brn', 'iyr': '2017', 'hgt': '191cm'}
Checking {'byr': '1932', 'hcl': 'z', 'hgt': '190cm', 'cid': '201', 'iyr': '2016', 'pid': '#02dfcc', 'ecl': '#6b9341', 'eyr': '2004'}
Bad expire year
Checking {'hcl': '#ceb3a1', 'iyr': '2013', 'hgt': '191cm', 'pid': '501799813', 'byr': '1993', 'ecl': 'hzl', 'eyr': '2020'}
Checking {'cid': '315', 'hcl': '#a97842', 'iyr': '2012', 'hgt': '179cm', 'pid': '897450687', 'byr': '1984', 'eyr': '2029', 'ecl': 'blu'}
Checking {'hcl': '#6b5442', 'iyr': '2011', 'hgt': '190in', 'pid': '299193732', 'byr': '1945', 'ecl': 'gry', 'eyr': '2020'}
Checking {'iyr': '2013', 'hcl': '#ceb3a1', 'hgt': '191cm', 'pid': '501799813', 'ecl': 'hzl', 'byr': '1993', 'eyr': '2020'}
Checking {'ecl': 'blu', 'cid': '315', 'pid': '897450687', 'hgt': '179cm', 'byr': '1984', 'eyr': '2029', 'iyr': '2012', 'hcl': '#a97842'}
Checking {'iyr': '2011', 'ecl': 'gry', 'hcl': '#6b5442', 'pid': '299193732', 'eyr': '2020', 'byr': '1945', 'hgt': '190in'}
bad height in inches: 190
Checking {'hcl': '#fffffd', 'iyr': '2017', 'hgt': '158cm', 'pid': '090738381', 'byr': '1992', 'eyr': '2022', 'ecl': 'oth'}
Checking {'cid': '92', 'hcl': '#573edf', 'iyr': '2016', 'hgt': '179cm', 'pid': '765588435', 'byr': '2002', 'ecl': 'amb', 'eyr': '2028'}
Checking {'hcl': '#967d2f', 'iyr': '2015', 'pid': '128081454', 'hgt': '190cm', 'eyr': '2025', 'ecl': 'oth'}
Checking {'hgt': '158cm', 'eyr': '2022', 'pid': '090738381', 'byr': '1992', 'iyr': '2017', 'hcl': '#fffffd', 'ecl': 'oth'}
Checking {'eyr': '2028', 'cid': '92', 'ecl': 'amb', 'hcl': '#573edf', 'pid': '765588435', 'iyr': '2016', 'hgt': '179cm', 'byr': '2002'}
Checking {'eyr': '2025', 'pid': '128081454', 'hcl': '#967d2f', 'hgt': '190cm', 'iyr': '2015', 'ecl': 'oth'}
Missing expected value
Checking {'cid': '239', 'hcl': '#888785', 'iyr': '2019', 'hgt': '189cm', 'byr': '1993', 'pid': '001825574', 'eyr': '2025', 'ecl': 'gry'}
Checking {'hcl': 'z', 'iyr': '1971', 'hgt': '100', 'byr': '2013', 'pid': '0758189515', 'eyr': '2034', 'ecl': 'gry'}
Checking {'hgt': '189cm', 'eyr': '2025', 'ecl': 'gry', 'hcl': '#888785', 'byr': '1993', 'pid': '001825574', 'cid': '239', 'iyr': '2019'}
Checking {'byr': '2013', 'pid': '0758189515', 'hcl': 'z', 'eyr': '2034', 'iyr': '1971', 'ecl': 'gry', 'hgt': '100'}
Bad birth year
Checking {'hcl': '#3638a2', 'iyr': '2011', 'hgt': '156cm', 'byr': '1943', 'pid': '539139386', 'eyr': '2026', 'ecl': 'hzl'}
Checking {'hcl': '#733820', 'iyr': '2017', 'hgt': '173cm', 'pid': '016597738', 'byr': '1956', 'eyr': '2030', 'ecl': 'brn'}
Checking {'hcl': '#cfa07d', 'iyr': '2018', 'hgt': '167cm', 'pid': '822607758', 'byr': '1974', 'eyr': '2028', 'ecl': 'brn'}
Checking {'hcl': '#efcc98', 'iyr': '2020', 'hgt': '65in', 'byr': '1980', 'pid': '397182705', 'eyr': '2020', 'ecl': 'oth'}
Checking {'hcl': '#ceb3a1', 'iyr': '2015', 'byr': '1954', 'pid': '398087239', 'eyr': '2024'}
Checking {'eyr': '2026', 'byr': '1943', 'hcl': '#3638a2', 'iyr': '2011', 'pid': '539139386', 'hgt': '156cm', 'ecl': 'hzl'}
Checking {'eyr': '2030', 'pid': '016597738', 'iyr': '2017', 'hgt': '173cm', 'ecl': 'brn', 'hcl': '#733820', 'byr': '1956'}
Checking {'eyr': '2028', 'iyr': '2018', 'pid': '822607758', 'hcl': '#cfa07d', 'ecl': 'brn', 'hgt': '167cm', 'byr': '1974'}
Checking {'eyr': '2020', 'byr': '1980', 'hgt': '65in', 'iyr': '2020', 'ecl': 'oth', 'hcl': '#efcc98', 'pid': '397182705'}
Checking {'iyr': '2015', 'byr': '1954', 'hcl': '#ceb3a1', 'eyr': '2024', 'pid': '398087239'}
Missing expected value
Checking {'ecl': 'zzz', 'hcl': '234fc4', 'iyr': '2015', 'hgt': '177in', 'pid': '159cm', 'byr': '2022', 'eyr': '2027', 'cid': '256'}
Checking {'cid': '256', 'hcl': '234fc4', 'ecl': 'zzz', 'hgt': '177in', 'eyr': '2027', 'iyr': '2015', 'pid': '159cm', 'byr': '2022'}
Bad birth year
Checking {'eyr': '2025', 'hcl': '#a928b0', 'iyr': '2018', 'hgt': '158cm', 'byr': '1976', 'pid': '920448637', 'cid': '209', 'ecl': 'hzl'}
Checking {'cid': '223', 'hcl': '#888785', 'iyr': '2016', 'hgt': '165cm', 'pid': '96925844', 'byr': '1984', 'eyr': '2030', 'ecl': 'gry'}
Checking {'iyr': '2018', 'cid': '209', 'hcl': '#a928b0', 'byr': '1976', 'ecl': 'hzl', 'pid': '920448637', 'eyr': '2025', 'hgt': '158cm'}
Checking {'pid': '96925844', 'iyr': '2016', 'eyr': '2030', 'hcl': '#888785', 'ecl': 'gry', 'byr': '1984', 'cid': '223', 'hgt': '165cm'}
bad pid
Checking {'hcl': '#18171d', 'iyr': '2014', 'hgt': '153cm', 'byr': '1964', 'pid': '831479208', 'eyr': '2024', 'ecl': 'brn'}
Checking {'hcl': '#ceb3a1', 'iyr': '2019', 'hgt': '185cm', 'byr': '1958', 'pid': '827043482', 'ecl': 'brn', 'eyr': '2026'}
Checking {'eyr': '2026', 'hcl': '#733820', 'iyr': '2020', 'hgt': '67in', 'pid': '426593479', 'byr': '1922', 'cid': '116', 'ecl': 'blu'}
Checking {'hcl': '#fffffd', 'iyr': '2019', 'hgt': '156cm', 'pid': '951768959', 'byr': '1969', 'eyr': '2022', 'cid': '330'}
Checking {'byr': '1964', 'pid': '831479208', 'hgt': '153cm', 'iyr': '2014', 'eyr': '2024', 'ecl': 'brn', 'hcl': '#18171d'}
Checking {'iyr': '2019', 'ecl': 'brn', 'hgt': '185cm', 'byr': '1958', 'hcl': '#ceb3a1', 'eyr': '2026', 'pid': '827043482'}
Checking {'iyr': '2020', 'hgt': '67in', 'cid': '116', 'hcl': '#733820', 'ecl': 'blu', 'pid': '426593479', 'byr': '1922', 'eyr': '2026'}
Checking {'eyr': '2022', 'hcl': '#fffffd', 'cid': '330', 'pid': '951768959', 'byr': '1969', 'iyr': '2019', 'hgt': '156cm'}
Missing expected value
Checking {'ecl': 'oth', 'hcl': '#111544', 'iyr': '2019', 'hgt': '151cm', 'byr': '1929', 'pid': '083495633', 'cid': '223', 'eyr': '2030'}
Checking {'iyr': '2016', 'byr': '1967', 'pid': '739606431', 'hgt': '166cm', 'eyr': '2025', 'ecl': 'blu'}
Checking {'eyr': '2030', 'ecl': 'oth', 'byr': '1929', 'hgt': '151cm', 'cid': '223', 'hcl': '#111544', 'pid': '083495633', 'iyr': '2019'}
Checking {'eyr': '2025', 'iyr': '2016', 'ecl': 'blu', 'hgt': '166cm', 'byr': '1967', 'pid': '739606431'}
Missing expected value
Checking {'hcl': '#ceb3a1', 'iyr': '2020', 'hgt': '161cm', 'pid': '788420638', 'byr': '1922', 'eyr': '2021', 'ecl': 'gry'}
Checking {'hcl': '#888785', 'byr': '1956', 'pid': '705051840', 'hgt': '158cm', 'eyr': '2025', 'ecl': 'oth'}
Checking {'eyr': '2021', 'ecl': 'gry', 'hcl': '#ceb3a1', 'pid': '788420638', 'byr': '1922', 'iyr': '2020', 'hgt': '161cm'}
Checking {'byr': '1956', 'eyr': '2025', 'hcl': '#888785', 'ecl': 'oth', 'pid': '705051840', 'hgt': '158cm'}
Missing expected value
Checking {'hcl': '#cfa07d', 'iyr': '2015', 'pid': '047851403', 'byr': '1937', 'hgt': '192cm', 'eyr': '2025'}
Checking {'pid': '047851403', 'byr': '1937', 'hcl': '#cfa07d', 'iyr': '2015', 'hgt': '192cm', 'eyr': '2025'}
Missing expected value
Checking {'eyr': '2022', 'hcl': '#c0946f', 'iyr': '2019', 'hgt': '178cm', 'byr': '1923', 'pid': '411527076', 'cid': '194', 'ecl': 'gry'}
Checking {'hcl': '#341e13', 'iyr': '2014', 'hgt': '186cm', 'byr': '1956', 'pid': '976268893', 'eyr': '2027', 'ecl': 'brn'}
Checking {'eyr': '2025', 'hcl': '#18171d', 'iyr': '2011', 'hgt': '183cm', 'byr': '1958', 'pid': '389943720', 'cid': '81', 'ecl': 'brn'}
Checking {'hcl': '#c0946f', 'byr': '1972', 'pid': '593351635', 'hgt': '165cm', 'eyr': '2028', 'ecl': 'amb'}
Checking {'hgt': '178cm', 'cid': '194', 'iyr': '2019', 'byr': '1923', 'hcl': '#c0946f', 'pid': '411527076', 'ecl': 'gry', 'eyr': '2022'}
Checking {'hgt': '186cm', 'iyr': '2014', 'byr': '1956', 'eyr': '2027', 'ecl': 'brn', 'pid': '976268893', 'hcl': '#341e13'}
Checking {'iyr': '2011', 'cid': '81', 'hcl': '#18171d', 'hgt': '183cm', 'byr': '1958', 'ecl': 'brn', 'eyr': '2025', 'pid': '389943720'}
Checking {'eyr': '2028', 'byr': '1972', 'ecl': 'amb', 'hcl': '#c0946f', 'pid': '593351635', 'hgt': '165cm'}
Missing expected value
Checking {'hcl': '#341e13', 'iyr': '2012', 'hgt': '169cm', 'byr': '1991', 'pid': '599766528', 'ecl': 'blu', 'cid': '156'}
Checking {'iyr': '2012', 'byr': '1991', 'ecl': 'blu', 'hcl': '#341e13', 'hgt': '169cm', 'cid': '156', 'pid': '599766528'}
Missing expected value
Checking {'ecl': 'zzz', 'iyr': '2001', 'hgt': '75cm', 'byr': '2029', 'pid': '319443119', 'eyr': '2020', 'cid': '306'}
Checking {'byr': '2029', 'hgt': '75cm', 'pid': '319443119', 'iyr': '2001', 'eyr': '2020', 'cid': '306', 'ecl': 'zzz'}
Missing expected value
Checking {'eyr': '2021', 'hcl': '#866857', 'iyr': '2014', 'hgt': '167cm', 'byr': '1948', 'pid': '256331758', 'cid': '273', 'ecl': 'grn'}
Checking {'cid': '241', 'hcl': '#733820', 'iyr': '2016', 'hgt': '158cm', 'byr': '1977', 'pid': '423680717', 'eyr': '2024', 'ecl': 'oth'}
Checking {'eyr': '2024', 'hcl': '#341e13', 'iyr': '2017', 'hgt': '185cm', 'pid': '788619400', 'byr': '1954', 'ecl': 'hzl', 'cid': '153'}
Checking {'hcl': '#cfa07d', 'iyr': '2016', 'hgt': '161cm', 'pid': '621023569', 'byr': '1928', 'ecl': 'blu', 'eyr': '2026'}
Checking {'ecl': 'xry', 'hcl': 'aa8fc8', 'iyr': '1951', 'hgt': '168in', 'byr': '2024', 'pid': '166cm', 'eyr': '1979', 'cid': '91'}
Checking {'hcl': '#866857', 'cid': '273', 'ecl': 'grn', 'byr': '1948', 'hgt': '167cm', 'iyr': '2014', 'pid': '256331758', 'eyr': '2021'}
Checking {'iyr': '2016', 'eyr': '2024', 'ecl': 'oth', 'hcl': '#733820', 'byr': '1977', 'pid': '423680717', 'hgt': '158cm', 'cid': '241'}
Checking {'hcl': '#341e13', 'pid': '788619400', 'byr': '1954', 'ecl': 'hzl', 'cid': '153', 'hgt': '185cm', 'eyr': '2024', 'iyr': '2017'}
Checking {'hcl': '#cfa07d', 'ecl': 'blu', 'hgt': '161cm', 'eyr': '2026', 'pid': '621023569', 'byr': '1928', 'iyr': '2016'}
Checking {'cid': '91', 'byr': '2024', 'hgt': '168in', 'iyr': '1951', 'ecl': 'xry', 'eyr': '1979', 'hcl': 'aa8fc8', 'pid': '166cm'}
Bad birth year
Checking {'cid': '155', 'hcl': '#18171d', 'iyr': '2012', 'hgt': '159cm', 'byr': '1952', 'pid': '875326712', 'ecl': 'brn', 'eyr': '2028'}
Checking {'hcl': '#733820', 'iyr': '2015', 'hgt': '163cm', 'byr': '1990', 'pid': '162682954', 'eyr': '2026', 'ecl': 'amb'}
Checking {'hcl': '#c0946f', 'iyr': '2020', 'hgt': '151cm', 'pid': '936952728', 'byr': '1969', 'ecl': 'brn', 'eyr': '2029'}
Checking {'hcl': '#866857', 'iyr': '2013', 'hgt': '189cm', 'pid': '132928469', 'byr': '1928', 'ecl': 'amb', 'eyr': '2026'}
Checking {'hcl': '#623a2f', 'iyr': '2012', 'hgt': '190cm', 'pid': '185240766', 'byr': '1952', 'ecl': 'grn', 'eyr': '2020'}
Checking {'cid': '64', 'hcl': 'z', 'iyr': '1935', 'hgt': '67cm', 'byr': '2021', 'pid': '4900748653', 'eyr': '2026', 'ecl': '#ef67e5'}
Checking {'eyr': '2028', 'cid': '155', 'hgt': '159cm', 'byr': '1952', 'pid': '875326712', 'ecl': 'brn', 'iyr': '2012', 'hcl': '#18171d'}
Checking {'eyr': '2026', 'hcl': '#733820', 'byr': '1990', 'hgt': '163cm', 'ecl': 'amb', 'iyr': '2015', 'pid': '162682954'}
Checking {'iyr': '2020', 'pid': '936952728', 'byr': '1969', 'ecl': 'brn', 'hgt': '151cm', 'hcl': '#c0946f', 'eyr': '2029'}
Checking {'hgt': '189cm', 'pid': '132928469', 'ecl': 'amb', 'hcl': '#866857', 'byr': '1928', 'eyr': '2026', 'iyr': '2013'}
Checking {'ecl': 'grn', 'pid': '185240766', 'iyr': '2012', 'hgt': '190cm', 'byr': '1952', 'hcl': '#623a2f', 'eyr': '2020'}
Checking {'byr': '2021', 'eyr': '2026', 'hgt': '67cm', 'ecl': '#ef67e5', 'hcl': 'z', 'iyr': '1935', 'pid': '4900748653', 'cid': '64'}
Bad birth year
Checking {'ecl': 'gry', 'hcl': '#7d3b0c', 'iyr': '2016', 'hgt': '69in', 'pid': '076116194', 'byr': '1979', 'cid': '248', 'eyr': '2022'}
Checking {'cid': '127', 'hcl': '#44e350', 'iyr': '2020', 'hgt': '180cm', 'byr': '1991', 'ecl': 'blu', 'eyr': '2021'}
Checking {'hgt': '69in', 'hcl': '#7d3b0c', 'cid': '248', 'eyr': '2022', 'pid': '076116194', 'byr': '1979', 'ecl': 'gry', 'iyr': '2016'}
Checking {'byr': '1991', 'eyr': '2021', 'hgt': '180cm', 'iyr': '2020', 'cid': '127', 'ecl': 'blu', 'hcl': '#44e350'}
Missing expected value
Checking {'hcl': '#733820', 'iyr': '2018', 'hgt': '150cm', 'byr': '1954', 'pid': '002868205', 'ecl': 'brn', 'eyr': '2021'}
Checking {'ecl': 'amb', 'hcl': '#623a2f', 'iyr': '2017', 'hgt': '170cm', 'pid': '524531652', 'byr': '1927', 'eyr': '2020', 'cid': '80'}
Checking {'ecl': 'blu', 'hcl': '#efcc98', 'iyr': '2018', 'hgt': '187cm', 'pid': '424660272', 'byr': '1970', 'eyr': '2021', 'cid': '238'}
Checking {'eyr': '2020', 'hcl': '#602927', 'iyr': '2013', 'hgt': '175cm', 'byr': '1923', 'pid': '946014113', 'cid': '273', 'ecl': 'brn'}
Checking {'eyr': '2022', 'hcl': '#6b5442', 'iyr': '2012', 'hgt': '71in', 'byr': '1929', 'pid': '581329373', 'cid': '88', 'ecl': 'gry'}
Checking {'ecl': 'oth', 'hcl': '#6b5442', 'iyr': '2017', 'hgt': '184', 'pid': '022131529', 'byr': '2005', 'cid': '79', 'eyr': '1960'}
Checking {'byr': '1954', 'hcl': '#733820', 'iyr': '2018', 'pid': '002868205', 'hgt': '150cm', 'ecl': 'brn', 'eyr': '2021'}
Checking {'pid': '524531652', 'hcl': '#623a2f', 'cid': '80', 'ecl': 'amb', 'iyr': '2017', 'eyr': '2020', 'hgt': '170cm', 'byr': '1927'}
Checking {'pid': '424660272', 'iyr': '2018', 'hcl': '#efcc98', 'eyr': '2021', 'cid': '238', 'hgt': '187cm', 'byr': '1970', 'ecl': 'blu'}
Checking {'byr': '1923', 'pid': '946014113', 'cid': '273', 'iyr': '2013', 'hgt': '175cm', 'ecl': 'brn', 'hcl': '#602927', 'eyr': '2020'}
Checking {'hcl': '#6b5442', 'cid': '88', 'ecl': 'gry', 'iyr': '2012', 'byr': '1929', 'hgt': '71in', 'eyr': '2022', 'pid': '581329373'}
Checking {'eyr': '1960', 'ecl': 'oth', 'iyr': '2017', 'pid': '022131529', 'cid': '79', 'hgt': '184', 'byr': '2005', 'hcl': '#6b5442'}
Bad birth year
Checking {'hcl': '#fffffd', 'iyr': '2011', 'hgt': '60in', 'pid': '422677836', 'byr': '1925', 'eyr': '2030', 'ecl': 'gry'}
Checking {'eyr': '2026', 'hcl': '#18171d', 'iyr': '2011', 'hgt': '158cm', 'byr': '1971', 'pid': '517329528', 'cid': '325', 'ecl': 'hzl'}
Checking {'eyr': '2030', 'iyr': '2017', 'hgt': '176cm', 'byr': '1937', 'pid': '321795494', 'ecl': 'blu', 'cid': '259'}
Checking {'eyr': '2030', 'pid': '422677836', 'iyr': '2011', 'hcl': '#fffffd', 'byr': '1925', 'hgt': '60in', 'ecl': 'gry'}
Checking {'cid': '325', 'hgt': '158cm', 'byr': '1971', 'ecl': 'hzl', 'pid': '517329528', 'hcl': '#18171d', 'eyr': '2026', 'iyr': '2011'}
Checking {'byr': '1937', 'cid': '259', 'eyr': '2030', 'hgt': '176cm', 'ecl': 'blu', 'pid': '321795494', 'iyr': '2017'}
Missing expected value
Checking {'eyr': '2026', 'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '74in', 'pid': '551525002', 'byr': '1954', 'cid': '230', 'ecl': 'grn'}
Checking {'cid': '139', 'hcl': 'c39522', 'pid': '004366607', 'hgt': '66cm', 'ecl': '#21a3e9', 'eyr': '2024'}
Checking {'pid': '551525002', 'ecl': 'grn', 'eyr': '2026', 'iyr': '2013', 'cid': '230', 'hgt': '74in', 'hcl': '#cfa07d', 'byr': '1954'}
Checking {'pid': '004366607', 'hcl': 'c39522', 'hgt': '66cm', 'ecl': '#21a3e9', 'eyr': '2024', 'cid': '139'}
Missing expected value
Checking {'eyr': '2037', 'hcl': '0ee9d4', 'iyr': '1994', 'hgt': '158cm', 'byr': '2016', 'pid': '522572315', 'cid': '98', 'ecl': 'xry'}
Checking {'ecl': 'xry', 'eyr': '2037', 'byr': '2016', 'iyr': '1994', 'cid': '98', 'pid': '522572315', 'hgt': '158cm', 'hcl': '0ee9d4'}
Bad birth year
Checking {'eyr': '2028', 'hcl': '#142217', 'iyr': '2018', 'hgt': '179cm', 'pid': '073189127', 'byr': '1977', 'ecl': 'grn', 'cid': '70'}
Checking {'ecl': 'brn', 'hcl': '#733820', 'iyr': '2020', 'hgt': '64in', 'pid': '045852463', 'byr': '1948', 'eyr': '2020', 'cid': '69'}
Checking {'ecl': 'brn', 'hcl': '#733820', 'iyr': '2011', 'hgt': '178cm', 'byr': '1970', 'pid': '512594967', 'cid': '268', 'eyr': '2025'}
Checking {'hcl': '#18171d', 'iyr': '2014', 'byr': '1950', 'pid': '329927551', 'hgt': '161cm', 'eyr': '2025'}
Checking {'cid': '70', 'eyr': '2028', 'hgt': '179cm', 'pid': '073189127', 'ecl': 'grn', 'iyr': '2018', 'hcl': '#142217', 'byr': '1977'}
Checking {'pid': '045852463', 'cid': '69', 'iyr': '2020', 'ecl': 'brn', 'byr': '1948', 'eyr': '2020', 'hgt': '64in', 'hcl': '#733820'}
Checking {'cid': '268', 'byr': '1970', 'eyr': '2025', 'hgt': '178cm', 'pid': '512594967', 'iyr': '2011', 'ecl': 'brn', 'hcl': '#733820'}
Checking {'eyr': '2025', 'hcl': '#18171d', 'iyr': '2014', 'byr': '1950', 'hgt': '161cm', 'pid': '329927551'}
Missing expected value
Checking {'cid': '100', 'hcl': '#a97842', 'iyr': '2010', 'hgt': '163cm', 'byr': '1956', 'pid': '965746490', 'eyr': '2024', 'ecl': 'brn'}
Checking {'ecl': 'grn', 'hcl': '#602927', 'iyr': '2011', 'hgt': '190cm', 'pid': '864571411', 'byr': '1962', 'cid': '112', 'eyr': '2027'}
Checking {'cid': '54', 'hcl': '#6b5442', 'iyr': '2011', 'hgt': '159cm', 'byr': '1922', 'pid': '689641249', 'eyr': '2025', 'ecl': 'gry'}
Checking {'cid': '323', 'iyr': '2020', 'hgt': '158cm', 'pid': '876082513', 'byr': '1941', 'ecl': 'hzl', 'eyr': '2028'}
Checking {'byr': '1956', 'eyr': '2024', 'hgt': '163cm', 'pid': '965746490', 'hcl': '#a97842', 'ecl': 'brn', 'cid': '100', 'iyr': '2010'}
Checking {'cid': '112', 'eyr': '2027', 'pid': '864571411', 'hgt': '190cm', 'iyr': '2011', 'byr': '1962', 'ecl': 'grn', 'hcl': '#602927'}
Checking {'ecl': 'gry', 'cid': '54', 'iyr': '2011', 'hcl': '#6b5442', 'byr': '1922', 'eyr': '2025', 'pid': '689641249', 'hgt': '159cm'}
Checking {'eyr': '2028', 'cid': '323', 'iyr': '2020', 'hgt': '158cm', 'ecl': 'hzl', 'pid': '876082513', 'byr': '1941'}
Missing expected value
Checking {'cid': '226', 'hcl': '#18171d', 'iyr': '2014', 'hgt': '160cm', 'pid': '910116712', 'byr': '1927', 'ecl': 'oth', 'eyr': '2023'}
Checking {'ecl': 'grn', 'hcl': '#602927', 'iyr': '2030', 'hgt': '186cm', 'byr': '1963', 'pid': '706533329', 'cid': '183', 'eyr': '2030'}
Checking {'hcl': '#18171d', 'hgt': '160cm', 'pid': '910116712', 'ecl': 'oth', 'iyr': '2014', 'byr': '1927', 'eyr': '2023', 'cid': '226'}
Checking {'iyr': '2030', 'hcl': '#602927', 'eyr': '2030', 'ecl': 'grn', 'cid': '183', 'hgt': '186cm', 'byr': '1963', 'pid': '706533329'}
Bad issue year
Checking {'ecl': 'hzl', 'hcl': '#866857', 'iyr': '2015', 'hgt': '150cm', 'byr': '1958', 'pid': '120633047', 'cid': '279', 'eyr': '2026'}
Checking {'hcl': '#733820', 'iyr': '2019', 'hgt': '187cm', 'byr': '1989', 'pid': '470596304', 'ecl': 'hzl', 'eyr': '2022'}
Checking {'cid': '346', 'hcl': '#888785', 'iyr': '2013', 'hgt': '167cm', 'byr': '1994', 'pid': '528844948', 'ecl': 'hzl', 'eyr': '2027'}
Checking {'hcl': '#fffffd', 'iyr': '2014', 'hgt': '192cm', 'pid': '969181309', 'byr': '1970', 'eyr': '2025', 'ecl': 'amb'}
Checking {'hcl': '#341e13', 'iyr': '2012', 'hgt': '167cm', 'pid': '053348609', 'byr': '1931', 'eyr': '2026', 'ecl': 'oth'}
Checking {'hcl': '#fffffd', 'iyr': '2013', 'hgt': '182cm', 'pid': '030276279', 'byr': '1967', 'eyr': '2029', 'ecl': 'grn'}
Checking {'cid': '224', 'hcl': '#ceb3a1', 'iyr': '2016', 'hgt': '177cm', 'byr': '1949', 'pid': '745439371', 'eyr': '2022', 'ecl': 'oth'}
Checking {'hcl': '#341e13', 'iyr': '2016', 'hgt': '64in', 'byr': '1940', 'pid': '351021541', 'eyr': '2028', 'ecl': 'amb'}
Checking {'eyr': '2021', 'hcl': '#866857', 'iyr': '2019', 'hgt': '74in', 'pid': '698666542', 'byr': '1953', 'cid': '309', 'ecl': 'oth'}
Checking {'ecl': 'brn', 'hcl': '#733820', 'iyr': '2013', 'hgt': '186cm', 'byr': '1979', 'pid': '727367898', 'cid': '236', 'eyr': '2023'}
Checking {'cid': '245', 'hcl': '#623a2f', 'iyr': '2016', 'hgt': '65cm', 'byr': '1956', 'pid': '371685442', 'eyr': '2025', 'ecl': 'oth'}
Checking {'cid': '279', 'eyr': '2026', 'iyr': '2015', 'byr': '1958', 'pid': '120633047', 'hgt': '150cm', 'ecl': 'hzl', 'hcl': '#866857'}
Checking {'iyr': '2019', 'byr': '1989', 'hcl': '#733820', 'ecl': 'hzl', 'pid': '470596304', 'hgt': '187cm', 'eyr': '2022'}
Checking {'eyr': '2027', 'hcl': '#888785', 'cid': '346', 'iyr': '2013', 'hgt': '167cm', 'ecl': 'hzl', 'byr': '1994', 'pid': '528844948'}
Checking {'hcl': '#fffffd', 'pid': '969181309', 'iyr': '2014', 'hgt': '192cm', 'eyr': '2025', 'byr': '1970', 'ecl': 'amb'}
Checking {'eyr': '2026', 'iyr': '2012', 'hcl': '#341e13', 'ecl': 'oth', 'pid': '053348609', 'byr': '1931', 'hgt': '167cm'}
Checking {'eyr': '2029', 'ecl': 'grn', 'pid': '030276279', 'iyr': '2013', 'hgt': '182cm', 'hcl': '#fffffd', 'byr': '1967'}
Checking {'byr': '1949', 'eyr': '2022', 'hcl': '#ceb3a1', 'iyr': '2016', 'ecl': 'oth', 'hgt': '177cm', 'cid': '224', 'pid': '745439371'}
Checking {'iyr': '2016', 'byr': '1940', 'eyr': '2028', 'pid': '351021541', 'hcl': '#341e13', 'ecl': 'amb', 'hgt': '64in'}
Checking {'cid': '309', 'hgt': '74in', 'pid': '698666542', 'hcl': '#866857', 'ecl': 'oth', 'byr': '1953', 'iyr': '2019', 'eyr': '2021'}
Checking {'iyr': '2013', 'byr': '1979', 'eyr': '2023', 'hgt': '186cm', 'ecl': 'brn', 'cid': '236', 'pid': '727367898', 'hcl': '#733820'}
Checking {'hgt': '65cm', 'byr': '1956', 'eyr': '2025', 'pid': '371685442', 'iyr': '2016', 'ecl': 'oth', 'cid': '245', 'hcl': '#623a2f'}
bad height in cm
Checking {'hcl': '#888785', 'iyr': '2010', 'hgt': '155cm', 'byr': '1927', 'pid': '916070590', 'ecl': 'grn', 'eyr': '2027'}
Checking {'eyr': '2022', 'hcl': '#866857', 'iyr': '2019', 'hgt': '179cm', 'byr': '1993', 'pid': '354895012', 'ecl': 'blu', 'cid': '332'}
Checking {'eyr': '2025', 'hcl': '#efcc98', 'iyr': '2029', 'hgt': '69cm', 'pid': '179cm', 'byr': '2007', 'cid': '216', 'ecl': 'oth'}
Checking {'hgt': '155cm', 'ecl': 'grn', 'hcl': '#888785', 'eyr': '2027', 'iyr': '2010', 'byr': '1927', 'pid': '916070590'}
Checking {'hgt': '179cm', 'ecl': 'blu', 'hcl': '#866857', 'byr': '1993', 'iyr': '2019', 'cid': '332', 'eyr': '2022', 'pid': '354895012'}
Checking {'iyr': '2029', 'hgt': '69cm', 'hcl': '#efcc98', 'pid': '179cm', 'cid': '216', 'byr': '2007', 'ecl': 'oth', 'eyr': '2025'}
Bad birth year
Checking {'hcl': 'z', 'iyr': '1988', 'hgt': '187', 'byr': '2020', 'pid': '225115160', 'ecl': '#30e67c', 'eyr': '2037'}
Checking {'iyr': '1988', 'hgt': '187', 'hcl': 'z', 'ecl': '#30e67c', 'byr': '2020', 'pid': '225115160', 'eyr': '2037'}
Bad birth year
Checking {'iyr': '2011', 'byr': '1965', 'pid': '455044780', 'hgt': '188cm', 'eyr': '2021', 'ecl': 'hzl'}
Checking {'eyr': '2021', 'iyr': '2011', 'hgt': '188cm', 'ecl': 'hzl', 'byr': '1965', 'pid': '455044780'}
Missing expected value
Checking {'hcl': '#fffffd', 'iyr': '2016', 'hgt': '61in', 'pid': '750994177', 'byr': '2002', 'ecl': 'gry', 'eyr': '2023'}
Checking {'hcl': '#18171d', 'iyr': '2020', 'hgt': '177cm', 'pid': '304482618', 'byr': '1955', 'ecl': 'gry', 'eyr': '2027'}
Checking {'ecl': 'oth', 'hcl': '#b6652a', 'iyr': '2017', 'hgt': '187cm', 'byr': '1981', 'pid': '795201673', 'eyr': '2020', 'cid': '154'}
Checking {'cid': '101', 'hcl': '#cfa07d', 'iyr': '2019', 'hgt': '151cm', 'byr': '1954', 'pid': '930011749', 'eyr': '2026', 'ecl': 'gry'}
Checking {'eyr': '1955', 'hcl': 'z', 'iyr': '2030', 'pid': '#d45ed4', 'byr': '1999', 'cid': '338', 'ecl': 'zzz'}
Checking {'ecl': 'gry', 'pid': '750994177', 'byr': '2002', 'iyr': '2016', 'eyr': '2023', 'hgt': '61in', 'hcl': '#fffffd'}
Checking {'iyr': '2020', 'ecl': 'gry', 'pid': '304482618', 'hcl': '#18171d', 'eyr': '2027', 'byr': '1955', 'hgt': '177cm'}
Checking {'hgt': '187cm', 'byr': '1981', 'pid': '795201673', 'eyr': '2020', 'cid': '154', 'hcl': '#b6652a', 'iyr': '2017', 'ecl': 'oth'}
Checking {'ecl': 'gry', 'byr': '1954', 'hgt': '151cm', 'iyr': '2019', 'cid': '101', 'eyr': '2026', 'hcl': '#cfa07d', 'pid': '930011749'}
Checking {'ecl': 'zzz', 'eyr': '1955', 'pid': '#d45ed4', 'cid': '338', 'iyr': '2030', 'hcl': 'z', 'byr': '1999'}
Missing expected value
Checking {'cid': '125', 'hcl': '#7d3b0c', 'iyr': '2018', 'hgt': '166cm', 'pid': '861636258', 'byr': '1958', 'eyr': '2020', 'ecl': 'brn'}
Checking {'hcl': '#7d3b0c', 'iyr': '2014', 'hgt': '67', 'byr': '1935', 'pid': '409864761', 'eyr': '2022', 'ecl': 'brn'}
Checking {'eyr': '2020', 'pid': '861636258', 'hgt': '166cm', 'hcl': '#7d3b0c', 'ecl': 'brn', 'iyr': '2018', 'cid': '125', 'byr': '1958'}
Checking {'iyr': '2014', 'eyr': '2022', 'hgt': '67', 'hcl': '#7d3b0c', 'ecl': 'brn', 'byr': '1935', 'pid': '409864761'}
bad height generally
Checking {'eyr': '2022', 'hcl': '#866857', 'iyr': '2012', 'hgt': '178cm', 'pid': '483584137', 'byr': '2000', 'cid': '94', 'ecl': 'blu'}
Checking {'hcl': '#602927', 'iyr': '2015', 'hgt': '184cm', 'byr': '1946', 'pid': '947292495', 'ecl': 'hzl', 'eyr': '2028'}
Checking {'ecl': 'gry', 'hcl': '#6b5442', 'iyr': '2014', 'hgt': '59in', 'byr': '1974', 'pid': '358779220', 'cid': '96', 'eyr': '2028'}
Checking {'eyr': '2022', 'hcl': '#61154f', 'byr': '1932', 'hgt': '167cm', 'ecl': 'brn', 'cid': '126'}
Checking {'hcl': '#866857', 'iyr': '2012', 'cid': '94', 'pid': '483584137', 'byr': '2000', 'ecl': 'blu', 'hgt': '178cm', 'eyr': '2022'}
Checking {'byr': '1946', 'ecl': 'hzl', 'iyr': '2015', 'eyr': '2028', 'hgt': '184cm', 'hcl': '#602927', 'pid': '947292495'}
Checking {'byr': '1974', 'cid': '96', 'hgt': '59in', 'eyr': '2028', 'pid': '358779220', 'hcl': '#6b5442', 'ecl': 'gry', 'iyr': '2014'}
Checking {'hcl': '#61154f', 'byr': '1932', 'hgt': '167cm', 'ecl': 'brn', 'cid': '126', 'eyr': '2022'}
Missing expected value
Checking {'hcl': '#866857', 'iyr': '2014', 'hgt': '169cm', 'byr': '1926', 'pid': '463772660', 'ecl': 'gry', 'eyr': '2020'}
Checking {'cid': '111', 'hcl': '#fffffd', 'iyr': '2010', 'hgt': '191cm', 'pid': '654733578', 'byr': '1943', 'eyr': '2024', 'ecl': 'hzl'}
Checking {'hcl': '#c0946f', 'iyr': '2026', 'pid': '164776417', 'byr': '1977', 'hgt': '74cm', 'eyr': '2021'}
Checking {'ecl': 'gry', 'iyr': '2014', 'hgt': '169cm', 'byr': '1926', 'eyr': '2020', 'hcl': '#866857', 'pid': '463772660'}
Checking {'pid': '654733578', 'ecl': 'hzl', 'cid': '111', 'iyr': '2010', 'hcl': '#fffffd', 'eyr': '2024', 'hgt': '191cm', 'byr': '1943'}
Checking {'eyr': '2021', 'hgt': '74cm', 'hcl': '#c0946f', 'iyr': '2026', 'pid': '164776417', 'byr': '1977'}
Missing expected value
Checking {'eyr': '1949', 'hcl': 'z', 'iyr': '1921', 'pid': '442332495', 'byr': '2018', 'ecl': '#6db74f', 'cid': '101'}
Checking {'ecl': '#6db74f', 'iyr': '1921', 'pid': '442332495', 'byr': '2018', 'hcl': 'z', 'cid': '101', 'eyr': '1949'}
Missing expected value
Checking {'ecl': 'blu', 'hcl': '518816', 'iyr': '1939', 'hgt': '191cm', 'byr': '2022', 'pid': '10107923', 'eyr': '2038', 'cid': '332'}
Checking {'cid': '332', 'byr': '2022', 'ecl': 'blu', 'eyr': '2038', 'iyr': '1939', 'hcl': '518816', 'hgt': '191cm', 'pid': '10107923'}
Bad birth year
Checking {'hcl': '#733820', 'iyr': '2010', 'hgt': '183cm', 'pid': '168853141', 'byr': '1996', 'eyr': '2021', 'ecl': 'hzl'}
Checking {'cid': '89', 'hcl': '336a3b', 'iyr': '2016', 'hgt': '62in', 'pid': '556617728', 'byr': '2029', 'eyr': '2023', 'ecl': 'xry'}
Checking {'pid': '168853141', 'iyr': '2010', 'eyr': '2021', 'byr': '1996', 'ecl': 'hzl', 'hgt': '183cm', 'hcl': '#733820'}
Checking {'hgt': '62in', 'pid': '556617728', 'hcl': '336a3b', 'eyr': '2023', 'byr': '2029', 'ecl': 'xry', 'iyr': '2016', 'cid': '89'}
Bad birth year
Checking {'eyr': '2023', 'hcl': '#efcc98', 'iyr': '2020', 'hgt': '181cm', 'pid': '075811396', 'byr': '1960', 'ecl': 'hzl', 'cid': '297'}
Checking {'hcl': '#602927', 'iyr': '2015', 'byr': '1995', 'hgt': '75in', 'eyr': '2030', 'ecl': 'brn'}
Checking {'ecl': 'hzl', 'hcl': '#efcc98', 'iyr': '2020', 'cid': '297', 'hgt': '181cm', 'pid': '075811396', 'eyr': '2023', 'byr': '1960'}
Checking {'eyr': '2030', 'hcl': '#602927', 'ecl': 'brn', 'iyr': '2015', 'hgt': '75in', 'byr': '1995'}
Missing expected value
Checking {'cid': '237', 'hcl': '#8936bb', 'iyr': '2015', 'hgt': '183cm', 'byr': '1998', 'eyr': '2028', 'ecl': 'grn'}
Checking {'ecl': 'grn', 'cid': '237', 'hcl': '#8936bb', 'hgt': '183cm', 'eyr': '2028', 'iyr': '2015', 'byr': '1998'}
Missing expected value
Checking {'hcl': '#efcc98', 'pid': '550427102', 'byr': '1991', 'hgt': '67in', 'ecl': 'gry'}
Checking {'pid': '550427102', 'hgt': '67in', 'byr': '1991', 'ecl': 'gry', 'hcl': '#efcc98'}
Missing expected value
Checking {'ecl': 'gmt', 'hcl': '00f05b', 'iyr': '2022', 'hgt': '70cm', 'byr': '1948', 'cid': '274', 'eyr': '1961'}
Checking {'cid': '274', 'hgt': '70cm', 'iyr': '2022', 'eyr': '1961', 'hcl': '00f05b', 'byr': '1948', 'ecl': 'gmt'}
Missing expected value
Checking {'cid': '150', 'hcl': '#18171d', 'iyr': '2018', 'hgt': '153cm', 'pid': '831302208', 'byr': '1927', 'ecl': 'blu', 'eyr': '2020'}
Checking {'ecl': 'blu', 'hcl': '#ceb3a1', 'iyr': '2018', 'hgt': '192cm', 'byr': '1973', 'pid': '770473271', 'cid': '215', 'eyr': '2027'}
Checking {'hcl': '#623a2f', 'iyr': '2019', 'hgt': '174cm', 'byr': '1962', 'pid': '589533254', 'eyr': '2021', 'ecl': 'hzl'}
Checking {'hcl': '#a97842', 'iyr': '2012', 'hgt': '184cm', 'byr': '1991', 'pid': '677889195', 'ecl': 'hzl', 'cid': '292'}
Checking {'ecl': 'blu', 'iyr': '2018', 'hgt': '153cm', 'eyr': '2020', 'pid': '831302208', 'byr': '1927', 'hcl': '#18171d', 'cid': '150'}
Checking {'iyr': '2018', 'byr': '1973', 'hcl': '#ceb3a1', 'cid': '215', 'hgt': '192cm', 'pid': '770473271', 'eyr': '2027', 'ecl': 'blu'}
Checking {'iyr': '2019', 'eyr': '2021', 'hcl': '#623a2f', 'ecl': 'hzl', 'hgt': '174cm', 'byr': '1962', 'pid': '589533254'}
Checking {'iyr': '2012', 'ecl': 'hzl', 'hgt': '184cm', 'cid': '292', 'byr': '1991', 'pid': '677889195', 'hcl': '#a97842'}
Missing expected value
Checking {'hcl': 'z', 'iyr': '2010', 'hgt': '154in', 'pid': '#4f47c3', 'byr': '2022', 'cid': '69', 'ecl': '#e36a65'}
Checking {'iyr': '2010', 'pid': '#4f47c3', 'hgt': '154in', 'cid': '69', 'hcl': 'z', 'byr': '2022', 'ecl': '#e36a65'}
Missing expected value
Checking {'hcl': '#b6652a', 'iyr': '2016', 'hgt': '171cm', 'pid': '499582878', 'byr': '1930', 'ecl': '#5ff50c', 'eyr': '2024'}
Checking {'ecl': '#5ff50c', 'pid': '499582878', 'hcl': '#b6652a', 'hgt': '171cm', 'iyr': '2016', 'byr': '1930', 'eyr': '2024'}
bad eye color
Checking {'hcl': '#6b5442', 'iyr': '2015', 'hgt': '159cm', 'byr': '1936', 'pid': '658019126', 'eyr': '2028', 'ecl': 'amb'}
Checking {'cid': '239', 'hcl': '#18171d', 'iyr': '2013', 'hgt': '158cm', 'byr': '1928', 'pid': '599970280', 'eyr': '2026', 'ecl': 'grn'}
Checking {'hcl': '#c0946f', 'iyr': '2018', 'pid': '684820830', 'hgt': '182cm', 'ecl': 'oth', 'eyr': '2023'}
Checking {'hgt': '159cm', 'byr': '1936', 'eyr': '2028', 'hcl': '#6b5442', 'ecl': 'amb', 'iyr': '2015', 'pid': '658019126'}
Checking {'byr': '1928', 'pid': '599970280', 'eyr': '2026', 'ecl': 'grn', 'hgt': '158cm', 'hcl': '#18171d', 'cid': '239', 'iyr': '2013'}
Checking {'pid': '684820830', 'hgt': '182cm', 'ecl': 'oth', 'hcl': '#c0946f', 'eyr': '2023', 'iyr': '2018'}
Missing expected value
Checking {'eyr': '2021', 'hcl': '#602927', 'iyr': '2019', 'hgt': '71in', 'pid': '668361647', 'byr': '1952', 'ecl': 'blu', 'cid': '348'}
Checking {'cid': '193', 'hcl': '#7d5994', 'iyr': '2010', 'hgt': '165cm', 'pid': '256350027', 'byr': '1947', 'ecl': 'grn', 'eyr': '2030'}
Checking {'eyr': '2029', 'hcl': '#602927', 'iyr': '2019', 'hgt': '153cm', 'byr': '1931', 'pid': '911300650', 'cid': '118', 'ecl': 'gry'}
Checking {'hcl': '#866857', 'iyr': '2016', 'hgt': '154cm', 'pid': '515526226', 'byr': '1936', 'eyr': '2025', 'ecl': 'grn'}
Checking {'hcl': '#623a2f', 'iyr': '2019', 'hgt': '160cm', 'pid': '932621460', 'byr': '1990', 'ecl': 'oth', 'eyr': '2030'}
Checking {'eyr': '2027', 'hcl': '#623a2f', 'iyr': '2016', 'hgt': '176cm', 'pid': '662549708', 'byr': '1949', 'cid': '277', 'ecl': 'blu'}
Checking {'iyr': '2010', 'byr': '1947', 'pid': '223603325', 'eyr': '2021', 'ecl': 'gry'}
Checking {'iyr': '2019', 'ecl': 'blu', 'pid': '668361647', 'cid': '348', 'byr': '1952', 'hcl': '#602927', 'eyr': '2021', 'hgt': '71in'}
Checking {'hgt': '165cm', 'ecl': 'grn', 'eyr': '2030', 'iyr': '2010', 'pid': '256350027', 'hcl': '#7d5994', 'cid': '193', 'byr': '1947'}
Checking {'hcl': '#602927', 'iyr': '2019', 'ecl': 'gry', 'eyr': '2029', 'byr': '1931', 'cid': '118', 'hgt': '153cm', 'pid': '911300650'}
Checking {'eyr': '2025', 'hgt': '154cm', 'hcl': '#866857', 'iyr': '2016', 'ecl': 'grn', 'pid': '515526226', 'byr': '1936'}
Checking {'hcl': '#623a2f', 'hgt': '160cm', 'iyr': '2019', 'ecl': 'oth', 'pid': '932621460', 'eyr': '2030', 'byr': '1990'}
Checking {'hcl': '#623a2f', 'ecl': 'blu', 'eyr': '2027', 'cid': '277', 'pid': '662549708', 'byr': '1949', 'iyr': '2016', 'hgt': '176cm'}
Checking {'iyr': '2010', 'eyr': '2021', 'byr': '1947', 'pid': '223603325', 'ecl': 'gry'}
Missing expected value
Checking {'hcl': '#733820', 'iyr': '2020', 'hgt': '183cm', 'pid': '145738978', 'byr': '1949', 'ecl': 'gry', 'eyr': '2029'}
Checking {'hcl': '#a97842', 'iyr': '2011', 'hgt': '63in', 'byr': '1941', 'pid': '091089766', 'eyr': '2028', 'ecl': 'gry'}
Checking {'eyr': '2021', 'hcl': '#fffffd', 'iyr': '2020', 'hgt': '157cm', 'byr': '1978', 'pid': '242258232', 'ecl': 'hzl', 'cid': '275'}
Checking {'cid': '132', 'hcl': '#733820', 'iyr': '2011', 'hgt': '192cm', 'pid': '239061408', 'byr': '1949', 'ecl': 'oth', 'eyr': '2023'}
Checking {'eyr': '2021', 'hcl': '#341e13', 'iyr': '2014', 'hgt': '152cm', 'byr': '1954', 'pid': '667414305', 'cid': '282', 'ecl': 'brn'}
Checking {'hcl': '#7d3b0c', 'iyr': '2018', 'hgt': '186cm', 'pid': '745564182', 'byr': '1935', 'eyr': '2028', 'ecl': 'gry'}
Checking {'hcl': 'd26483', 'iyr': '2014', 'hgt': '163cm', 'byr': '1972', 'pid': '611712147', 'eyr': '2026', 'ecl': '#57d27c'}
Checking {'ecl': 'gry', 'pid': '145738978', 'eyr': '2029', 'iyr': '2020', 'hcl': '#733820', 'byr': '1949', 'hgt': '183cm'}
Checking {'hgt': '63in', 'eyr': '2028', 'iyr': '2011', 'hcl': '#a97842', 'byr': '1941', 'ecl': 'gry', 'pid': '091089766'}
Checking {'hcl': '#fffffd', 'cid': '275', 'hgt': '157cm', 'eyr': '2021', 'byr': '1978', 'ecl': 'hzl', 'iyr': '2020', 'pid': '242258232'}
Checking {'pid': '239061408', 'ecl': 'oth', 'eyr': '2023', 'iyr': '2011', 'hgt': '192cm', 'byr': '1949', 'hcl': '#733820', 'cid': '132'}
Checking {'byr': '1954', 'hgt': '152cm', 'ecl': 'brn', 'pid': '667414305', 'eyr': '2021', 'cid': '282', 'iyr': '2014', 'hcl': '#341e13'}
Checking {'iyr': '2018', 'pid': '745564182', 'hgt': '186cm', 'eyr': '2028', 'hcl': '#7d3b0c', 'byr': '1935', 'ecl': 'gry'}
Checking {'iyr': '2014', 'eyr': '2026', 'hcl': 'd26483', 'byr': '1972', 'pid': '611712147', 'hgt': '163cm', 'ecl': '#57d27c'}
bad hair color
Checking {'eyr': '2025', 'hcl': '#cfa07d', 'iyr': '2020', 'hgt': '158cm', 'byr': '1937', 'pid': '150255302', 'ecl': 'blu', 'cid': '322'}
Checking {'cid': '116', 'hcl': '#866857', 'iyr': '2011', 'hgt': '155cm', 'byr': '1974', 'pid': '755213661', 'eyr': '2030', 'ecl': 'blu'}
Checking {'hcl': '#866857', 'iyr': '2014', 'hgt': '166cm', 'pid': '679616797', 'byr': '1999', 'ecl': 'gry', 'eyr': '2025'}
Checking {'hcl': '#fffffd', 'iyr': '2019', 'pid': '835993614', 'byr': '1920', 'hgt': '158cm', 'eyr': '2028'}
Checking {'cid': '322', 'eyr': '2025', 'byr': '1937', 'iyr': '2020', 'ecl': 'blu', 'hcl': '#cfa07d', 'hgt': '158cm', 'pid': '150255302'}
Checking {'eyr': '2030', 'iyr': '2011', 'hcl': '#866857', 'byr': '1974', 'ecl': 'blu', 'pid': '755213661', 'hgt': '155cm', 'cid': '116'}
Checking {'hcl': '#866857', 'pid': '679616797', 'ecl': 'gry', 'hgt': '166cm', 'byr': '1999', 'iyr': '2014', 'eyr': '2025'}
Checking {'iyr': '2019', 'hcl': '#fffffd', 'hgt': '158cm', 'eyr': '2028', 'pid': '835993614', 'byr': '1920'}
Missing expected value
Checking {'eyr': '2025', 'hcl': '#200aaa', 'iyr': '2013', 'hgt': '151cm', 'pid': '742320152', 'byr': '1931', 'cid': '63', 'ecl': 'brn'}
Checking {'ecl': 'xry', 'hcl': '#615954', 'iyr': '2014', 'hgt': '150cm', 'byr': '1950', 'pid': '596469710', 'eyr': '2027', 'cid': '155'}
Checking {'ecl': 'brn', 'pid': '742320152', 'iyr': '2013', 'hgt': '151cm', 'eyr': '2025', 'cid': '63', 'byr': '1931', 'hcl': '#200aaa'}
Checking {'byr': '1950', 'cid': '155', 'ecl': 'xry', 'hgt': '150cm', 'iyr': '2014', 'eyr': '2027', 'hcl': '#615954', 'pid': '596469710'}
bad eye color
Checking {'eyr': '2021', 'hcl': '#18171d', 'iyr': '2016', 'hgt': '166cm', 'byr': '1946', 'pid': '267318602', 'ecl': 'gry', 'cid': '261'}
Checking {'hcl': '#b6652a', 'iyr': '2013', 'hgt': '185cm', 'pid': '092573029', 'byr': '1956', 'ecl': 'gry', 'eyr': '2023'}
Checking {'hcl': '#efcc98', 'iyr': '2014', 'hgt': '172cm', 'byr': '1997', 'pid': '337403043', 'eyr': '2021', 'ecl': 'blu'}
Checking {'iyr': '2015', 'byr': '1949', 'pid': '230935940', 'hgt': '190cm', 'eyr': '2023'}
Checking {'byr': '1946', 'hgt': '166cm', 'ecl': 'gry', 'hcl': '#18171d', 'cid': '261', 'iyr': '2016', 'pid': '267318602', 'eyr': '2021'}
Checking {'ecl': 'gry', 'hgt': '185cm', 'iyr': '2013', 'pid': '092573029', 'eyr': '2023', 'byr': '1956', 'hcl': '#b6652a'}
Checking {'byr': '1997', 'hgt': '172cm', 'eyr': '2021', 'iyr': '2014', 'pid': '337403043', 'ecl': 'blu', 'hcl': '#efcc98'}
Checking {'hgt': '190cm', 'iyr': '2015', 'byr': '1949', 'eyr': '2023', 'pid': '230935940'}
Missing expected value
Checking {'hcl': '#a97842', 'iyr': '2017', 'hgt': '171cm', 'byr': '1980', 'pid': '9435249395', 'eyr': '2021', 'ecl': 'oth'}
Checking {'byr': '1980', 'hgt': '171cm', 'eyr': '2021', 'pid': '9435249395', 'ecl': 'oth', 'hcl': '#a97842', 'iyr': '2017'}
bad pid
Checking {'cid': '93', 'hcl': '#b6652a', 'iyr': '1923', 'hgt': '186cm', 'byr': '2011', 'pid': '239188418', 'eyr': '2039', 'ecl': 'hzl'}
Checking {'byr': '2011', 'hcl': '#b6652a', 'eyr': '2039', 'ecl': 'hzl', 'iyr': '1923', 'hgt': '186cm', 'pid': '239188418', 'cid': '93'}
Bad birth year
Checking {'eyr': '2028', 'hcl': '#602927', 'iyr': '2020', 'hgt': '160cm', 'pid': '791787662', 'byr': '1975', 'cid': '51', 'ecl': 'gry'}
Checking {'hcl': '#a97842', 'iyr': '2016', 'hgt': '183cm', 'pid': '720900081', 'byr': '1978', 'ecl': 'amb', 'eyr': '2022'}
Checking {'cid': '345', 'hcl': '#18171d', 'iyr': '2017', 'hgt': '157cm', 'pid': '628454234', 'byr': '1988', 'eyr': '2027', 'ecl': 'gry'}
Checking {'hcl': '#341e13', 'iyr': '2013', 'hgt': '66in', 'byr': '1985', 'pid': '996422540', 'ecl': 'grn', 'eyr': '2020'}
Checking {'cid': '214', 'hcl': '#866857', 'iyr': '2017', 'hgt': '161cm', 'pid': '186cm', 'byr': '1988', 'ecl': 'brn', 'eyr': '2022'}
Checking {'pid': '791787662', 'cid': '51', 'ecl': 'gry', 'hcl': '#602927', 'hgt': '160cm', 'iyr': '2020', 'eyr': '2028', 'byr': '1975'}
Checking {'ecl': 'amb', 'pid': '720900081', 'byr': '1978', 'hcl': '#a97842', 'hgt': '183cm', 'iyr': '2016', 'eyr': '2022'}
Checking {'eyr': '2027', 'hgt': '157cm', 'pid': '628454234', 'hcl': '#18171d', 'ecl': 'gry', 'iyr': '2017', 'cid': '345', 'byr': '1988'}
Checking {'byr': '1985', 'pid': '996422540', 'iyr': '2013', 'hgt': '66in', 'ecl': 'grn', 'eyr': '2020', 'hcl': '#341e13'}
Checking {'eyr': '2022', 'pid': '186cm', 'cid': '214', 'iyr': '2017', 'hcl': '#866857', 'ecl': 'brn', 'byr': '1988', 'hgt': '161cm'}
bad pid
Checking {'ecl': 'grn', 'hcl': '#18171d', 'iyr': '2019', 'hgt': '154cm', 'pid': '752184592', 'byr': '1966', 'eyr': '2025', 'cid': '119'}
Checking {'eyr': '2024', 'hcl': '#b6652a', 'iyr': '2011', 'hgt': '59in', 'byr': '1974', 'pid': '477922277', 'ecl': 'grn', 'cid': '100'}
Checking {'hcl': '#6b5442', 'iyr': '2013', 'hgt': '184cm', 'byr': '1969', 'pid': '514127885', 'ecl': 'brn', 'eyr': '2023'}
Checking {'cid': '111', 'hcl': '#cfa07d', 'iyr': '2020', 'hgt': '64in', 'byr': '1923', 'ecl': 'gry', 'eyr': '2029'}
Checking {'iyr': '2019', 'eyr': '2025', 'pid': '752184592', 'hgt': '154cm', 'byr': '1966', 'hcl': '#18171d', 'cid': '119', 'ecl': 'grn'}
Checking {'hcl': '#b6652a', 'cid': '100', 'byr': '1974', 'pid': '477922277', 'eyr': '2024', 'ecl': 'grn', 'iyr': '2011', 'hgt': '59in'}
Checking {'iyr': '2013', 'ecl': 'brn', 'hgt': '184cm', 'eyr': '2023', 'byr': '1969', 'pid': '514127885', 'hcl': '#6b5442'}
Checking {'hcl': '#cfa07d', 'iyr': '2020', 'byr': '1923', 'ecl': 'gry', 'hgt': '64in', 'eyr': '2029', 'cid': '111'}
Missing expected value
Checking {'ecl': 'blu', 'hcl': '#866857', 'iyr': '2016', 'hgt': '73in', 'byr': '1921', 'pid': '971490088', 'eyr': '2025', 'cid': '271'}
Checking {'cid': '63', 'hcl': '#602927', 'iyr': '2019', 'hgt': '179cm', 'byr': '1953', 'pid': '226869705', 'ecl': 'oth', 'eyr': '2023'}
Checking {'hcl': '#341e13', 'iyr': '2010', 'hgt': '175cm', 'byr': '1938', 'pid': '718683561', 'ecl': 'hzl', 'eyr': '2021'}
Checking {'hcl': 'z', 'iyr': '2023', 'hgt': '189in', 'byr': '2030', 'pid': '171cm', 'ecl': '#447c00', 'eyr': '2022'}
Checking {'byr': '1921', 'hgt': '73in', 'pid': '971490088', 'iyr': '2016', 'eyr': '2025', 'hcl': '#866857', 'cid': '271', 'ecl': 'blu'}
Checking {'ecl': 'oth', 'eyr': '2023', 'iyr': '2019', 'hgt': '179cm', 'byr': '1953', 'pid': '226869705', 'hcl': '#602927', 'cid': '63'}
Checking {'hgt': '175cm', 'ecl': 'hzl', 'iyr': '2010', 'byr': '1938', 'eyr': '2021', 'pid': '718683561', 'hcl': '#341e13'}
Checking {'iyr': '2023', 'hgt': '189in', 'byr': '2030', 'pid': '171cm', 'ecl': '#447c00', 'hcl': 'z', 'eyr': '2022'}
Bad birth year
Checking {'cid': '99', 'hcl': '#888785', 'iyr': '2020', 'hgt': '191cm', 'pid': '128824091', 'byr': '1982', 'ecl': 'blu', 'eyr': '2026'}
Checking {'hcl': '#fffffd', 'iyr': '2017', 'hgt': '151cm', 'pid': '333173949', 'byr': '1928', 'eyr': '2026', 'ecl': 'oth'}
Checking {'cid': '168', 'hcl': '#6b5442', 'iyr': '2016', 'hgt': '158cm', 'byr': '1945', 'pid': '888990994', 'eyr': '2026', 'ecl': 'grn'}
Checking {'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '168cm', 'byr': '1931', 'pid': '716975878', 'ecl': 'grn', 'eyr': '2023'}
Checking {'hcl': '#888785', 'iyr': '2020', 'hgt': '161cm', 'pid': '815050555', 'byr': '1980', 'ecl': 'blu', 'eyr': '2025'}
Checking {'hcl': '#7d3b0c', 'iyr': '2017', 'hgt': '171cm', 'pid': '470039281', 'byr': '1967', 'ecl': 'gry', 'eyr': '2021'}
Checking {'hcl': '#bdf8d6', 'iyr': '2018', 'hgt': '184cm', 'byr': '1954', 'pid': '694267794', 'eyr': '2030', 'ecl': 'blu'}
Checking {'hcl': '#cfa07d', 'iyr': '2016', 'hgt': '167cm', 'byr': '1971', 'pid': '237865320', 'ecl': 'brn', 'eyr': '2027'}
Checking {'cid': '215', 'hcl': '#a97842', 'iyr': '2014', 'hgt': '176cm', 'byr': '1921', 'pid': '186145415', 'ecl': 'oth', 'eyr': '2028'}
Checking {'hcl': '#7d3b0c', 'pid': '925805272', 'hgt': '65in', 'eyr': '2030', 'ecl': 'blu'}
Checking {'ecl': 'blu', 'eyr': '2026', 'hgt': '191cm', 'iyr': '2020', 'hcl': '#888785', 'pid': '128824091', 'cid': '99', 'byr': '1982'}
Checking {'eyr': '2026', 'pid': '333173949', 'iyr': '2017', 'ecl': 'oth', 'byr': '1928', 'hcl': '#fffffd', 'hgt': '151cm'}
Checking {'hcl': '#6b5442', 'ecl': 'grn', 'byr': '1945', 'pid': '888990994', 'cid': '168', 'eyr': '2026', 'iyr': '2016', 'hgt': '158cm'}
Checking {'ecl': 'grn', 'iyr': '2013', 'byr': '1931', 'pid': '716975878', 'hgt': '168cm', 'hcl': '#cfa07d', 'eyr': '2023'}
Checking {'pid': '815050555', 'ecl': 'blu', 'hgt': '161cm', 'hcl': '#888785', 'eyr': '2025', 'iyr': '2020', 'byr': '1980'}
Checking {'pid': '470039281', 'byr': '1967', 'iyr': '2017', 'ecl': 'gry', 'eyr': '2021', 'hgt': '171cm', 'hcl': '#7d3b0c'}
Checking {'hcl': '#bdf8d6', 'iyr': '2018', 'byr': '1954', 'eyr': '2030', 'ecl': 'blu', 'hgt': '184cm', 'pid': '694267794'}
Checking {'hcl': '#cfa07d', 'byr': '1971', 'ecl': 'brn', 'iyr': '2016', 'hgt': '167cm', 'eyr': '2027', 'pid': '237865320'}
Checking {'byr': '1921', 'eyr': '2028', 'iyr': '2014', 'pid': '186145415', 'cid': '215', 'ecl': 'oth', 'hgt': '176cm', 'hcl': '#a97842'}
Checking {'pid': '925805272', 'hcl': '#7d3b0c', 'eyr': '2030', 'hgt': '65in', 'ecl': 'blu'}
Missing expected value
Checking {'eyr': '2024', 'hcl': '#c0946f', 'iyr': '2013', 'hgt': '65in', 'byr': '1992', 'pid': '092712496', 'cid': '278', 'ecl': 'oth'}
Checking {'ecl': 'brn', 'hcl': '#18171d', 'iyr': '2018', 'hgt': '151cm', 'byr': '1971', 'pid': '599220575', 'cid': '321', 'eyr': '2030'}
Checking {'hcl': '#b6652a', 'iyr': '2016', 'byr': '1956', 'pid': '109381754', 'ecl': 'hzl', 'cid': '233'}
Checking {'byr': '1992', 'cid': '278', 'ecl': 'oth', 'hgt': '65in', 'hcl': '#c0946f', 'iyr': '2013', 'pid': '092712496', 'eyr': '2024'}
Checking {'hgt': '151cm', 'iyr': '2018', 'hcl': '#18171d', 'byr': '1971', 'pid': '599220575', 'cid': '321', 'eyr': '2030', 'ecl': 'brn'}
Checking {'byr': '1956', 'iyr': '2016', 'hcl': '#b6652a', 'pid': '109381754', 'ecl': 'hzl', 'cid': '233'}
Missing expected value
Checking {'hcl': '#866857', 'iyr': '2015', 'hgt': '152cm', 'byr': '1988', 'pid': '274656754', 'ecl': 'amb', 'eyr': '2022'}
Checking {'ecl': 'amb', 'hcl': '#733820', 'iyr': '2013', 'hgt': '186cm', 'byr': '1947', 'pid': '165847317', 'cid': '285', 'eyr': '2028'}
Checking {'cid': '183', 'hcl': '#866857', 'pid': '601229952', 'hgt': '191cm', 'eyr': '2023', 'ecl': 'brn'}
Checking {'iyr': '2015', 'byr': '1988', 'hcl': '#866857', 'ecl': 'amb', 'pid': '274656754', 'hgt': '152cm', 'eyr': '2022'}
Checking {'eyr': '2028', 'ecl': 'amb', 'cid': '285', 'byr': '1947', 'hgt': '186cm', 'pid': '165847317', 'hcl': '#733820', 'iyr': '2013'}
Checking {'hcl': '#866857', 'pid': '601229952', 'eyr': '2023', 'ecl': 'brn', 'hgt': '191cm', 'cid': '183'}
Missing expected value
Checking {'hcl': '#b50bab', 'iyr': '2018', 'hgt': '191cm', 'byr': '1936', 'pid': '422563929', 'eyr': '2025', 'ecl': 'oth'}
Checking {'hcl': '#a97842', 'iyr': '2010', 'hgt': '181cm', 'byr': '1971', 'pid': '267796608', 'ecl': 'gry', 'eyr': '2025'}
Checking {'cid': '301', 'hcl': '#0fd3b0', 'iyr': '2014', 'hgt': '173cm', 'pid': '606512017', 'byr': '1999', 'eyr': '2030', 'ecl': 'oth'}
Checking {'ecl': 'grn', 'hcl': '#602927', 'iyr': '2018', 'hgt': '179cm', 'byr': '1937', 'pid': '148179917', 'cid': '277', 'eyr': '2029'}
Checking {'hcl': '#7d3b0c', 'iyr': '2015', 'hgt': '162cm', 'byr': '1960', 'pid': '014246579', 'ecl': 'hzl', 'eyr': '2023'}
Checking {'hcl': '#777876', 'iyr': '2011', 'hgt': '188cm', 'byr': '1955', 'pid': '988764375', 'ecl': 'blu', 'eyr': '2020'}
Checking {'hcl': '#18171d', 'iyr': '2012', 'hgt': '173cm', 'pid': '524961020', 'byr': '1983', 'ecl': 'amb', 'eyr': '2028'}
Checking {'hcl': '#efcc98', 'iyr': '2019', 'hgt': '153cm', 'pid': '127759635', 'byr': '1932', 'ecl': 'hzl', 'eyr': '2020'}
Checking {'hcl': '#c0946f', 'iyr': '2013', 'pid': '421725637', 'byr': '1971', 'eyr': '2025', 'ecl': 'gry'}
Checking {'hgt': '191cm', 'iyr': '2018', 'hcl': '#b50bab', 'byr': '1936', 'eyr': '2025', 'pid': '422563929', 'ecl': 'oth'}
Checking {'ecl': 'gry', 'eyr': '2025', 'hgt': '181cm', 'hcl': '#a97842', 'byr': '1971', 'iyr': '2010', 'pid': '267796608'}
Checking {'hcl': '#0fd3b0', 'eyr': '2030', 'iyr': '2014', 'ecl': 'oth', 'pid': '606512017', 'hgt': '173cm', 'cid': '301', 'byr': '1999'}
Checking {'byr': '1937', 'cid': '277', 'pid': '148179917', 'hgt': '179cm', 'hcl': '#602927', 'iyr': '2018', 'eyr': '2029', 'ecl': 'grn'}
Checking {'hcl': '#7d3b0c', 'byr': '1960', 'ecl': 'hzl', 'hgt': '162cm', 'iyr': '2015', 'pid': '014246579', 'eyr': '2023'}
Checking {'ecl': 'blu', 'eyr': '2020', 'iyr': '2011', 'byr': '1955', 'hcl': '#777876', 'hgt': '188cm', 'pid': '988764375'}
Checking {'iyr': '2012', 'ecl': 'amb', 'hcl': '#18171d', 'pid': '524961020', 'byr': '1983', 'hgt': '173cm', 'eyr': '2028'}
Checking {'hgt': '153cm', 'hcl': '#efcc98', 'pid': '127759635', 'iyr': '2019', 'byr': '1932', 'ecl': 'hzl', 'eyr': '2020'}
Checking {'eyr': '2025', 'pid': '421725637', 'ecl': 'gry', 'iyr': '2013', 'hcl': '#c0946f', 'byr': '1971'}
Missing expected value
Checking {'hcl': '#866857', 'iyr': '2015', 'hgt': '163cm', 'pid': '654033544', 'byr': '1923', 'cid': '176', 'ecl': 'brn'}
Checking {'iyr': '2015', 'pid': '654033544', 'cid': '176', 'hgt': '163cm', 'byr': '1923', 'ecl': 'brn', 'hcl': '#866857'}
Missing expected value
Checking {'cid': '128', 'hcl': '#623a2f', 'iyr': '2007', 'hgt': '76cm', 'byr': '2013', 'pid': '122621229', 'ecl': '#5cd4a8', 'eyr': '2035'}
Checking {'hcl': '#623a2f', 'byr': '2013', 'hgt': '76cm', 'ecl': '#5cd4a8', 'iyr': '2007', 'eyr': '2035', 'cid': '128', 'pid': '122621229'}
Bad birth year
Checking {'hcl': '#927794', 'iyr': '2019', 'hgt': '158cm', 'byr': '1964', 'pid': '269737193', 'ecl': 'oth', 'eyr': '2025'}
Checking {'ecl': 'blu', 'hcl': '#341e13', 'iyr': '2014', 'hgt': '174cm', 'byr': '1949', 'pid': '120077363', 'eyr': '2026', 'cid': '181'}
Checking {'ecl': 'oth', 'hcl': 'z', 'iyr': '2011', 'hgt': '151cm', 'pid': '638178037', 'byr': '1920', 'cid': '161', 'eyr': '2024'}
Checking {'hcl': '#927794', 'iyr': '2019', 'byr': '1964', 'hgt': '158cm', 'ecl': 'oth', 'pid': '269737193', 'eyr': '2025'}
Checking {'iyr': '2014', 'cid': '181', 'ecl': 'blu', 'byr': '1949', 'hcl': '#341e13', 'eyr': '2026', 'pid': '120077363', 'hgt': '174cm'}
Checking {'cid': '161', 'eyr': '2024', 'hcl': 'z', 'pid': '638178037', 'hgt': '151cm', 'byr': '1920', 'ecl': 'oth', 'iyr': '2011'}
bad hair color
Checking {'eyr': '2023', 'hcl': '#a97842', 'iyr': '2014', 'hgt': '161cm', 'byr': '1977', 'pid': '177001463', 'cid': '79', 'ecl': 'brn'}
Checking {'hcl': '#888785', 'iyr': '2010', 'hgt': '183cm', 'byr': '1938', 'pid': '302413712', 'eyr': '1967', 'ecl': 'grn'}
Checking {'ecl': 'brn', 'eyr': '2023', 'hgt': '161cm', 'hcl': '#a97842', 'byr': '1977', 'cid': '79', 'pid': '177001463', 'iyr': '2014'}
Checking {'byr': '1938', 'eyr': '1967', 'ecl': 'grn', 'pid': '302413712', 'hcl': '#888785', 'hgt': '183cm', 'iyr': '2010'}
Bad expire year
Checking {'hcl': '#c0946f', 'iyr': '2015', 'hgt': '164cm', 'byr': '1955', 'pid': '772380994', 'eyr': '2025', 'ecl': 'amb'}
Checking {'cid': '161', 'hcl': '#602927', 'iyr': '2019', 'hgt': '171cm', 'byr': '1924', 'ecl': 'amb', 'eyr': '2021'}
Checking {'hgt': '164cm', 'byr': '1955', 'pid': '772380994', 'iyr': '2015', 'hcl': '#c0946f', 'eyr': '2025', 'ecl': 'amb'}
Checking {'hcl': '#602927', 'eyr': '2021', 'byr': '1924', 'hgt': '171cm', 'cid': '161', 'ecl': 'amb', 'iyr': '2019'}
Missing expected value
Checking {'hcl': '7d1404', 'iyr': '2027', 'hgt': '119', 'pid': '143311761', 'byr': '1939', 'eyr': '1957', 'ecl': '#de1d21'}
Checking {'hgt': '119', 'hcl': '7d1404', 'eyr': '1957', 'pid': '143311761', 'iyr': '2027', 'byr': '1939', 'ecl': '#de1d21'}
Bad issue year
Checking {'hcl': '#ceb3a1', 'iyr': '2015', 'hgt': '182cm', 'pid': '136552613', 'byr': '1992', 'ecl': 'blu', 'cid': '205'}
Checking {'hgt': '182cm', 'iyr': '2015', 'ecl': 'blu', 'cid': '205', 'pid': '136552613', 'hcl': '#ceb3a1', 'byr': '1992'}
Missing expected value
Checking {'eyr': '2034', 'hcl': 'z', 'iyr': '2013', 'hgt': '172cm', 'byr': '1998', 'pid': '#ec3c3a', 'ecl': 'blu', 'cid': '54'}
Checking {'ecl': 'blu', 'iyr': '2013', 'cid': '54', 'byr': '1998', 'hcl': 'z', 'hgt': '172cm', 'eyr': '2034', 'pid': '#ec3c3a'}
Bad expire year
Checking {'hcl': '#623a2f', 'iyr': '2012', 'byr': '1975', 'pid': '358585328', 'ecl': 'blu', 'eyr': '2025'}
Checking {'byr': '1975', 'ecl': 'blu', 'eyr': '2025', 'hcl': '#623a2f', 'pid': '358585328', 'iyr': '2012'}
Missing expected value
Checking {'eyr': '2024', 'hcl': '#18171d', 'iyr': '2020', 'hgt': '190cm', 'pid': '282306278', 'byr': '1958', 'ecl': 'grn', 'cid': '276'}
Checking {'hcl': '#6b5442', 'iyr': '2017', 'hgt': '177cm', 'byr': '1955', 'pid': '111002386', 'eyr': '2028', 'ecl': 'grn'}
Checking {'cid': '109', 'hcl': '#866857', 'iyr': '2018', 'hgt': '169cm', 'pid': '694088201', 'byr': '1957', 'eyr': '2026', 'ecl': 'amb'}
Checking {'hcl': '#6b5442', 'iyr': '2013', 'hgt': '171cm', 'byr': '1965', 'pid': '268169550', 'ecl': 'blu', 'eyr': '2021'}
Checking {'cid': '173', 'hcl': '#a97842', 'iyr': '2010', 'hgt': '191cm', 'pid': '803092066', 'byr': '1956', 'eyr': '2023', 'ecl': 'grn'}
Checking {'cid': '181', 'hcl': '#b6652a', 'iyr': '2012', 'hgt': '190cm', 'byr': '1991', 'pid': '946620993', 'eyr': '2024', 'ecl': 'gry'}
Checking {'ecl': 'oth', 'hcl': '#cfa07d', 'iyr': '2019', 'hgt': '175cm', 'pid': '062548271', 'cid': '75', 'eyr': '2022'}
Checking {'pid': '282306278', 'byr': '1958', 'ecl': 'grn', 'hgt': '190cm', 'iyr': '2020', 'hcl': '#18171d', 'cid': '276', 'eyr': '2024'}
Checking {'byr': '1955', 'eyr': '2028', 'iyr': '2017', 'hgt': '177cm', 'ecl': 'grn', 'pid': '111002386', 'hcl': '#6b5442'}
Checking {'eyr': '2026', 'pid': '694088201', 'hcl': '#866857', 'hgt': '169cm', 'byr': '1957', 'ecl': 'amb', 'iyr': '2018', 'cid': '109'}
Checking {'hgt': '171cm', 'ecl': 'blu', 'iyr': '2013', 'eyr': '2021', 'hcl': '#6b5442', 'byr': '1965', 'pid': '268169550'}
Checking {'pid': '803092066', 'eyr': '2023', 'iyr': '2010', 'hcl': '#a97842', 'ecl': 'grn', 'byr': '1956', 'hgt': '191cm', 'cid': '173'}
Checking {'eyr': '2024', 'iyr': '2012', 'byr': '1991', 'ecl': 'gry', 'pid': '946620993', 'hgt': '190cm', 'hcl': '#b6652a', 'cid': '181'}
Checking {'iyr': '2019', 'hcl': '#cfa07d', 'cid': '75', 'hgt': '175cm', 'eyr': '2022', 'pid': '062548271', 'ecl': 'oth'}
Missing expected value
Checking {'hcl': '#888785', 'iyr': '2014', 'byr': '1956', 'pid': '860561420', 'hgt': '176cm', 'cid': '262'}
Checking {'cid': '262', 'byr': '1956', 'iyr': '2014', 'pid': '860561420', 'hcl': '#888785', 'hgt': '176cm'}
Missing expected value
Checking {'hcl': '#efcc98', 'iyr': '2013', 'hgt': '188cm', 'pid': '828180303', 'byr': '1932', 'ecl': 'gry', 'eyr': '2028'}
Checking {'ecl': 'brn', 'hcl': '#341e13', 'iyr': '2012', 'hgt': '150cm', 'byr': '1992', 'pid': '644391775', 'cid': '292', 'eyr': '2029'}
Checking {'hcl': '#ceb3a1', 'iyr': '2013', 'hgt': '182cm', 'byr': '1982', 'pid': '625704144', 'ecl': 'grn', 'eyr': '2026'}
Checking {'hcl': '#812218', 'iyr': '2013', 'hgt': '150cm', 'byr': '1926', 'pid': '610910806', 'ecl': 'brn', 'eyr': '2025'}
Checking {'hcl': '#623a2f', 'iyr': '2017', 'hgt': '61in', 'byr': '1926', 'pid': '347974562', 'eyr': '2020', 'ecl': 'oth'}
Checking {'hcl': '#a97842', 'iyr': '2014', 'hgt': '185cm', 'byr': '1940', 'pid': '123961293', 'eyr': '2023', 'ecl': 'blu'}
Checking {'hcl': '#692e6c', 'iyr': '2011', 'hgt': '172cm', 'byr': '1984', 'pid': '342962046', 'eyr': '2020', 'ecl': 'grn'}
Checking {'eyr': '2023', 'hcl': '#b08932', 'iyr': '2019', 'hgt': '193cm', 'pid': '343331979', 'byr': '1985', 'ecl': 'blu', 'cid': '269'}
Checking {'hcl': '#fffffd', 'iyr': '2011', 'pid': '483091240', 'byr': '1988', 'ecl': 'blu', 'eyr': '2022'}
Checking {'hcl': '#efcc98', 'hgt': '188cm', 'pid': '828180303', 'iyr': '2013', 'byr': '1932', 'ecl': 'gry', 'eyr': '2028'}
Checking {'eyr': '2029', 'hcl': '#341e13', 'byr': '1992', 'ecl': 'brn', 'iyr': '2012', 'cid': '292', 'pid': '644391775', 'hgt': '150cm'}
Checking {'ecl': 'grn', 'hgt': '182cm', 'eyr': '2026', 'hcl': '#ceb3a1', 'byr': '1982', 'pid': '625704144', 'iyr': '2013'}
Checking {'byr': '1926', 'iyr': '2013', 'ecl': 'brn', 'hcl': '#812218', 'eyr': '2025', 'hgt': '150cm', 'pid': '610910806'}
Checking {'hgt': '61in', 'byr': '1926', 'iyr': '2017', 'eyr': '2020', 'ecl': 'oth', 'hcl': '#623a2f', 'pid': '347974562'}
Checking {'hgt': '185cm', 'eyr': '2023', 'ecl': 'blu', 'byr': '1940', 'pid': '123961293', 'iyr': '2014', 'hcl': '#a97842'}
Checking {'iyr': '2011', 'byr': '1984', 'hgt': '172cm', 'eyr': '2020', 'hcl': '#692e6c', 'ecl': 'grn', 'pid': '342962046'}
Checking {'ecl': 'blu', 'hcl': '#b08932', 'pid': '343331979', 'iyr': '2019', 'hgt': '193cm', 'byr': '1985', 'cid': '269', 'eyr': '2023'}
Checking {'hcl': '#fffffd', 'ecl': 'blu', 'pid': '483091240', 'iyr': '2011', 'eyr': '2022', 'byr': '1988'}
Missing expected value
Checking {'hcl': '#ceb3a1', 'iyr': '2019', 'hgt': '177cm', 'pid': '516533115', 'byr': '1922', 'cid': '294', 'ecl': 'amb'}
Checking {'iyr': '2019', 'hgt': '177cm', 'pid': '516533115', 'cid': '294', 'ecl': 'amb', 'hcl': '#ceb3a1', 'byr': '1922'}
Missing expected value
Checking {'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '193cm', 'byr': '1965', 'pid': '931305875', 'eyr': '2023', 'ecl': 'grn'}
Checking {'cid': '209', 'hcl': '#fffffd', 'iyr': '2019', 'hgt': '164cm', 'byr': '1944', 'pid': '141532765', 'ecl': 'hzl', 'eyr': '2029'}
Checking {'hcl': '#ceb3a1', 'iyr': '2013', 'hgt': '189cm', 'pid': '604140631', 'byr': '1935', 'ecl': 'brn', 'eyr': '2022'}
Checking {'eyr': '2027', 'hcl': '#888785', 'iyr': '2020', 'hgt': '152cm', 'byr': '1959', 'pid': '849438430', 'ecl': 'amb', 'cid': '287'}
Checking {'hcl': '#623a2f', 'iyr': '2018', 'hgt': '167cm', 'byr': '1988', 'pid': '470443459', 'eyr': '2029', 'ecl': 'brn'}
Checking {'eyr': '2021', 'hcl': '#341e13', 'iyr': '2012', 'hgt': '175cm', 'byr': '2027', 'pid': '271833606', 'ecl': 'hzl', 'cid': '276'}
Checking {'byr': '1965', 'eyr': '2023', 'hcl': '#cfa07d', 'iyr': '2013', 'hgt': '193cm', 'ecl': 'grn', 'pid': '931305875'}
Checking {'ecl': 'hzl', 'byr': '1944', 'hgt': '164cm', 'hcl': '#fffffd', 'iyr': '2019', 'eyr': '2029', 'pid': '141532765', 'cid': '209'}
Checking {'iyr': '2013', 'hgt': '189cm', 'ecl': 'brn', 'pid': '604140631', 'eyr': '2022', 'hcl': '#ceb3a1', 'byr': '1935'}
Checking {'ecl': 'amb', 'hcl': '#888785', 'byr': '1959', 'cid': '287', 'pid': '849438430', 'hgt': '152cm', 'eyr': '2027', 'iyr': '2020'}
Checking {'byr': '1988', 'hcl': '#623a2f', 'eyr': '2029', 'ecl': 'brn', 'iyr': '2018', 'hgt': '167cm', 'pid': '470443459'}
Checking {'cid': '276', 'hcl': '#341e13', 'eyr': '2021', 'iyr': '2012', 'ecl': 'hzl', 'hgt': '175cm', 'byr': '2027', 'pid': '271833606'}
Bad birth year
Checking {'hcl': '#623a2f', 'iyr': '2010', 'hgt': '164cm', 'pid': '970527839', 'byr': '1974', 'eyr': '2027', 'ecl': 'amb'}
Checking {'hcl': '#c0946f', 'iyr': '2013', 'byr': '1932', 'pid': '104193512', 'eyr': '2020', 'ecl': 'grn'}
Checking {'eyr': '2027', 'iyr': '2010', 'pid': '970527839', 'hgt': '164cm', 'byr': '1974', 'hcl': '#623a2f', 'ecl': 'amb'}
Checking {'eyr': '2020', 'ecl': 'grn', 'byr': '1932', 'iyr': '2013', 'pid': '104193512', 'hcl': '#c0946f'}
Missing expected value
Checking {'hcl': '#623a2f', 'iyr': '2020', 'hgt': '65in', 'byr': '1982', 'pid': '570953460', 'eyr': '2030', 'ecl': 'blu'}
Checking {'hcl': '#602927', 'iyr': '2019', 'hgt': '169cm', 'byr': '1922', 'pid': '803264417', 'eyr': '2020', 'ecl': 'grn'}
Checking {'hcl': '#866857', 'iyr': '2017', 'hgt': '170cm', 'byr': '1963', 'pid': '762546796', 'ecl': 'amb', 'eyr': '2028'}
Checking {'cid': '184', 'hcl': '#733820', 'iyr': '1980', 'hgt': '176cm', 'pid': '54291174', 'byr': '1974', 'ecl': 'gry', 'eyr': '2035'}
Checking {'eyr': '2030', 'byr': '1982', 'hgt': '65in', 'ecl': 'blu', 'hcl': '#623a2f', 'pid': '570953460', 'iyr': '2020'}
Checking {'eyr': '2020', 'byr': '1922', 'hcl': '#602927', 'pid': '803264417', 'iyr': '2019', 'ecl': 'grn', 'hgt': '169cm'}
Checking {'ecl': 'amb', 'hcl': '#866857', 'byr': '1963', 'hgt': '170cm', 'eyr': '2028', 'pid': '762546796', 'iyr': '2017'}
Checking {'eyr': '2035', 'pid': '54291174', 'cid': '184', 'iyr': '1980', 'hgt': '176cm', 'ecl': 'gry', 'hcl': '#733820', 'byr': '1974'}
Bad issue year
Checking {'eyr': '2028', 'hcl': '#c0946f', 'iyr': '2013', 'hgt': '63in', 'pid': '408646971', 'byr': '1951', 'cid': '84', 'ecl': 'amb'}
Checking {'hcl': '#6b5442', 'iyr': '2013', 'hgt': '170cm', 'byr': '1994', 'pid': '348959147', 'eyr': '2021', 'ecl': 'amb'}
Checking {'cid': '199', 'hcl': 'e7c520', 'iyr': '2017', 'hgt': '156cm', 'byr': '1957', 'pid': '890752588', 'ecl': 'hzl', 'eyr': '2025'}
Checking {'iyr': '2013', 'hcl': '#c0946f', 'pid': '408646971', 'hgt': '63in', 'cid': '84', 'byr': '1951', 'ecl': 'amb', 'eyr': '2028'}
Checking {'eyr': '2021', 'hcl': '#6b5442', 'byr': '1994', 'hgt': '170cm', 'ecl': 'amb', 'pid': '348959147', 'iyr': '2013'}
Checking {'byr': '1957', 'ecl': 'hzl', 'hgt': '156cm', 'pid': '890752588', 'eyr': '2025', 'hcl': 'e7c520', 'cid': '199', 'iyr': '2017'}
bad hair color
Checking {'eyr': '2024', 'hcl': '#733820', 'iyr': '2016', 'hgt': '169cm', 'pid': '661114936', 'byr': '1928', 'ecl': 'hzl', 'cid': '180'}
Checking {'hcl': '#6b5442', 'iyr': '2015', 'hgt': '179cm', 'byr': '1941', 'pid': '148063033', 'eyr': '2020', 'ecl': 'brn'}
Checking {'hcl': '#cfa07d', 'iyr': '1935', 'hgt': '59cm', 'pid': '14292032', 'byr': '2020', 'eyr': '1956', 'ecl': '#c9bc33'}
Checking {'hgt': '169cm', 'iyr': '2016', 'cid': '180', 'hcl': '#733820', 'eyr': '2024', 'ecl': 'hzl', 'pid': '661114936', 'byr': '1928'}
Checking {'iyr': '2015', 'eyr': '2020', 'byr': '1941', 'hgt': '179cm', 'pid': '148063033', 'hcl': '#6b5442', 'ecl': 'brn'}
Checking {'iyr': '1935', 'pid': '14292032', 'byr': '2020', 'eyr': '1956', 'ecl': '#c9bc33', 'hgt': '59cm', 'hcl': '#cfa07d'}
Bad birth year
Checking {'ecl': 'amb', 'hcl': '#733820', 'iyr': '2010', 'hgt': '165cm', 'pid': '312465756', 'byr': '1993', 'eyr': '2023', 'cid': '112'}
Checking {'hcl': 'z', 'iyr': '1963', 'hgt': '111', 'byr': '1964', 'pid': '#f5628c', 'eyr': '2032', 'ecl': 'grt'}
Checking {'hgt': '165cm', 'iyr': '2010', 'eyr': '2023', 'hcl': '#733820', 'pid': '312465756', 'cid': '112', 'byr': '1993', 'ecl': 'amb'}
Checking {'eyr': '2032', 'ecl': 'grt', 'iyr': '1963', 'byr': '1964', 'pid': '#f5628c', 'hcl': 'z', 'hgt': '111'}
Bad issue year
Checking {'eyr': '2023', 'hcl': '#623a2f', 'iyr': '2012', 'hgt': '169cm', 'pid': '809080900', 'byr': '1979', 'cid': '291', 'ecl': 'oth'}
Checking {'iyr': '2021', 'byr': '1967', 'pid': '2498700612', 'hgt': '59cm', 'eyr': '2033', 'ecl': 'gmt'}
Checking {'hgt': '169cm', 'iyr': '2012', 'hcl': '#623a2f', 'cid': '291', 'ecl': 'oth', 'pid': '809080900', 'byr': '1979', 'eyr': '2023'}
Checking {'iyr': '2021', 'eyr': '2033', 'ecl': 'gmt', 'hgt': '59cm', 'byr': '1967', 'pid': '2498700612'}
Missing expected value
Checking {'hcl': '#b6652a', 'iyr': '2013', 'byr': '1953', 'pid': '442586860', 'ecl': 'oth'}
Checking {'byr': '1953', 'ecl': 'oth', 'iyr': '2013', 'hcl': '#b6652a', 'pid': '442586860'}
Missing expected value
Checking {'hcl': '#866857', 'iyr': '2017', 'hgt': '151cm', 'pid': '095687847', 'byr': '1967', 'eyr': '2022', 'ecl': 'oth'}
Checking {'hcl': '#866857', 'iyr': '1930', 'hgt': '61cm', 'pid': '983640144', 'byr': '1991', 'ecl': 'hzl', 'eyr': '2024'}
Checking {'pid': '095687847', 'eyr': '2022', 'hgt': '151cm', 'byr': '1967', 'iyr': '2017', 'ecl': 'oth', 'hcl': '#866857'}
Checking {'hcl': '#866857', 'pid': '983640144', 'hgt': '61cm', 'ecl': 'hzl', 'byr': '1991', 'iyr': '1930', 'eyr': '2024'}
Bad issue year
Checking {'hcl': '#602927', 'iyr': '2013', 'hgt': '151cm', 'byr': '1992', 'pid': '812583062', 'ecl': 'oth', 'eyr': '2025'}
Checking {'ecl': 'oth', 'hcl': '#602927', 'eyr': '2025', 'iyr': '2013', 'hgt': '151cm', 'byr': '1992', 'pid': '812583062'}
count = 194

View File

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

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__repr__', '__setattr__', '__str__', 'longList', 'ofAttributes', 'onThatObject', 'thatWeWantToSet']
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__new__', '__repr__', '__setattr__', '__str__', 'longList', 'ofAttributes', 'onThatObject', 'thatWeWantToSet']
1
2
3

View File

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

View File

@ -0,0 +1,19 @@
class Foo():
@classmethod
def cm(cls):
print(f"{cls=}")
class Bar(Foo):
pass
class Baz(Foo):
@classmethod
def cm(cls):
print("(Baz)")
super().cm()
Bar.cm()
Bar().cm()
Baz.cm()
Baz().cm()

View File

@ -0,0 +1,6 @@
cls=<class '__main__.Bar'>
cls=<class '__main__.Bar'>
(Baz)
cls=<class '__main__.Baz'>
(Baz)
cls=<class '__main__.Baz'>

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

View File

@ -0,0 +1,18 @@
def decorate(func):
def _inner(a):
print('in')
a = func(a)
print('out')
return a
return _inner
def foo():
@decorate
def bar(a):
if a <= 0:
return 0
return bar(a-1)
bar(2)
foo()

View File

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

View File

@ -120,7 +120,7 @@ def aMethod(with_,args=None):
try:
aMethod()
except:
except as exception:
print(exception.arg)
aMethod("just the first")
@ -128,11 +128,11 @@ aMethod("the first","and the second")
aMethod(args="hello",with_="world")
try:
aMethod(foo="hello",with_="bar")
except:
except as exception:
print(exception.arg) # unrecognized keyword arg, from inner method
aMethod(*[1,2])
try:
aMethod(*[1,2,3])
except:
except as exception:
print(exception.arg) # too many arguments

View File

@ -20,7 +20,7 @@ del l[3]
print(l) # [1, 3, 4]
try:
del l[3]
except:
except as exception:
print(exception.arg) # List index out of range
let o = object()
@ -36,13 +36,13 @@ print(dir(o.foo.bar))
print(o.foo.bar.qux)
try:
print(o.foo.bar.baz)
except:
except as exception:
print(exception.arg) # AttributeError
del o.foo.bar
print(dir(o.foo))
try:
print(o.foo.bar)
except:
except as exception:
print(exception.arg) # AttributeError
del o.foo
del o

View File

@ -7,10 +7,10 @@ False
[1, 3, 4, 5]
[1, 3, 4]
list index out of range: 3
['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__repr__', '__setattr__', '__str__', 'baz', 'qux']
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__new__', '__repr__', '__setattr__', '__str__', 'baz', 'qux']
42
['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__repr__', '__setattr__', '__str__', 'qux']
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__new__', '__repr__', '__setattr__', '__str__', 'qux']
hi
'object' object has no attribute 'baz'
['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__repr__', '__setattr__', '__str__']
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__new__', '__repr__', '__setattr__', '__str__']
'object' object has no attribute 'bar'

View File

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

View File

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

View File

@ -0,0 +1,13 @@
for i in range(3):
try:
print('hello world')
if i == 1:
break
except ValueError:
print('value error')
else:
print('no error')
finally:
print('and done')
print('finished')

View File

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

View File

@ -0,0 +1,14 @@
try:
try:
print('hello world')
raise ValueError()
except 1/0:
print("oh no")
except ValueError:
print("value error")
finally:
print('this is the finally')
except ZeroDivisionError:
print('caught the zero div error')
print('done')

View File

@ -0,0 +1,4 @@
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):
except (TypeError, ValueError) as exception:
print("Caught a", repr(exception))
for i in exception.traceback:
let func, instr = i

View File

@ -0,0 +1,98 @@
import dis
import fileio
from collections import deque
def test_a():
def bar():
return "string" + 42
def foo():
return bar() * 4
foo()
def test_b():
let foo = {
'bar': {
'baz': None
}
}
print(foo['bar']['baz']['qux']['etc'])
def test_c():
import os
os.system(42)
def test_d():
let a = object()
a.name = '42'
let b = None
let c = object()
c.name = '42'
print(a.name, b.name, c.name)
def test_e():
let a = 1
let b = 2
class Confabulator:
def __add__(self,other):
return NotImplemented
let c = Confabulator()
let d = 4
let x = (a + b) @ (c + d)
def test_f():
class Thing:
def __init__(self, required):
pass
def __eq__(self, other):
raise ValueError("oh no")
Thing('a') == Thing()
def disrec(code, seen):
let next = deque()
next.append(code)
while next:
let co = next.popleft()
seen.add(co)
let offset = 0
for inst,size,operand in dis.examine(co):
let expr = dis.ip_to_expression(co, offset + size - 1)
if expr is not None:
let lineNo, start, midStart, midEnd, end = expr
if co.__file__:
let j = 1
with fileio.open(co.__file__,'r') as f:
let line = f.readlines()[lineNo-1].rstrip()
let i = 0
while i < len(line):
if line[i] not in ' \t': break
j++
i++
while i < len(line):
print(line[i],end='')
i++
print()
while j < start:
print(' ',end='')
j++
while j < midStart:
print('~',end='')
j++
while j < midEnd:
print('^',end='')
j++
while j < end:
print('~',end='')
j++
print()
if isinstance(operand,codeobject) and operand not in seen:
next.append(operand)
offset += size
for func_name in dir():
if func_name.startswith('test_'):
disrec(globals()[func_name].__code__,set())

View File

@ -0,0 +1,54 @@
foo()
~~~^~
return "string" + 42
~~~~~~~~~^~~~
return bar() * 4
~~~^~
return bar() * 4
~~~~~~^~~
print(foo['bar']['baz']['qux']['etc'])
~~~^~~~~~~
print(foo['bar']['baz']['qux']['etc'])
~~~~~~~~~~^~~~~~~
print(foo['bar']['baz']['qux']['etc'])
~~~~~~~~~~~~~~~~~^~~~~~~
print(foo['bar']['baz']['qux']['etc'])
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
print(foo['bar']['baz']['qux']['etc'])
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
os.system(42)
~~^~~~~~~
os.system(42)
~~~~~~~~~^~~~
let a = object()
~~~~~~^~
a.name = '42'
~~^^^^~~~~~~~
let c = object()
~~~~~~^~
c.name = '42'
~~^^^^~~~~~~~
print(a.name, b.name, c.name)
~^~~~~
print(a.name, b.name, c.name)
~^~~~~
print(a.name, b.name, c.name)
~^~~~~
print(a.name, b.name, c.name)
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
let c = Confabulator()
~~~~~~~~~~~~^~
let x = (a + b) @ (c + d)
~~^~~
let x = (a + b) @ (c + d)
~~^~~
let x = (a + b) @ (c + d)
~~~~~~~~^~~~~~~~~
Thing('a') == Thing()
~~~~~^~~~~
Thing('a') == Thing()
~~~~~^~
Thing('a') == Thing()
~~~~~~~~~~~^^~~~~~~~~
raise ValueError("oh no")
~~~~~~~~~~^~~~~~~~~

View File

@ -0,0 +1,38 @@
import math
def print_values(values):
for v in values:
# Avoiding doing just 'v' as we want this test to work in Python and Kuroko with identical results
# and Python will try to reduce the number of digits to the minimum required for disambiguity, which
# we don't currently support.
print(v.__format__('.16g'),v.__format__('f'),v.__format__('e'),v.__format__('#.16g'),v.__format__('+.4g'))
print_values([
float('75.5834073120020679681'),
float('75.5834073120020679681e-7'),
float('75.5834073120020679681e-24'),
float('75.5834073120020679681e80'),
float('75.5834073120020679681e300'),
float('75.0'),
float('0.005'),
float('0.0005'),
float('0.5'),
float('0.01'),
float('0.25'),
float('0.25')/2,
float('0.25')/4,
float('0.25')/8,
float('0.25')/16,
float('0.25')/2048,
float('0.25')/4096,
float('10000000253263163212.0'),
(10**60)/1,
float('20000000000000000'),
0.0,
-0.0,
math.inf,
-math.inf,
math.nan,
-math.nan,
float('123.45'),
])

View File

@ -0,0 +1,27 @@
75.58340731200207 75.583407 7.558341e+01 75.58340731200207 +75.58
7.558340731200207e-06 0.000008 7.558341e-06 7.558340731200207e-06 +7.558e-06
7.558340731200207e-23 0.000000 7.558341e-23 7.558340731200207e-23 +7.558e-23
7.558340731200207e+81 7558340731200206731762734930317738502291660148265284220384036778702184341124939776.000000 7.558341e+81 7.558340731200207e+81 +7.558e+81
7.558340731200207e+301 75583407312002066768461022261315172287297487251874586478724757817960934981634094788769653163852924763443651501309652569997165035925379465760402739890567710612092775360309017524288996057690996811122123668937191051711752654751620072621666259734026943606049685516409713620071805443138455356168154210369536.000000 7.558341e+301 7.558340731200207e+301 +7.558e+301
75 75.000000 7.500000e+01 75.00000000000000 +75
0.005 0.005000 5.000000e-03 0.005000000000000000 +0.005
0.0005 0.000500 5.000000e-04 0.0005000000000000000 +0.0005
0.5 0.500000 5.000000e-01 0.5000000000000000 +0.5
0.01 0.010000 1.000000e-02 0.01000000000000000 +0.01
0.25 0.250000 2.500000e-01 0.2500000000000000 +0.25
0.125 0.125000 1.250000e-01 0.1250000000000000 +0.125
0.0625 0.062500 6.250000e-02 0.06250000000000000 +0.0625
0.03125 0.031250 3.125000e-02 0.03125000000000000 +0.03125
0.015625 0.015625 1.562500e-02 0.01562500000000000 +0.01562
0.0001220703125 0.000122 1.220703e-04 0.0001220703125000000 +0.0001221
6.103515625e-05 0.000061 6.103516e-05 6.103515625000000e-05 +6.104e-05
1.000000025326316e+19 10000000253263163392.000000 1.000000e+19 1.000000025326316e+19 +1e+19
9.999999999999999e+59 999999999999999949387135297074018866963645011013410073083904.000000 1.000000e+60 9.999999999999999e+59 +1e+60
2e+16 20000000000000000.000000 2.000000e+16 2.000000000000000e+16 +2e+16
0 0.000000 0.000000e+00 0.000000000000000 +0
-0 -0.000000 -0.000000e+00 -0.000000000000000 -0
inf inf inf inf +inf
-inf -inf -inf -inf -inf
nan nan nan nan +nan
nan nan nan nan +nan
123.45 123.450000 1.234500e+02 123.4500000000000 +123.5

View File

@ -1,3 +1,3 @@
['__class__', '__dir__', '__eq__', '__format__', '__func__', '__getattr__', '__hash__', '__init__', '__module__', '__qualname__', '__repr__', '__setattr__', '__str__', '_dict']
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__getattr__', '__hash__', '__init__', '__init_subclass__', '__module__', '__new__', '__qualname__', '__repr__', '__setattr__', '__str__', '_dict']
1
['__class__', '__dir__', '__eq__', '__format__', '__func__', '__hash__', '__module__', '__qualname__', '__repr__', '__setattr__', '__str__', 'butts']
['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__init_subclass__', '__module__', '__new__', '__qualname__', '__repr__', '__setattr__', '__str__', 'butts']

View File

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

View File

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

View File

@ -1,2 +0,0 @@
'object' object has no attribute '__init__'
'object' object has no attribute '__init__'

View File

@ -0,0 +1,15 @@
class Foo:
def __init_subclass__(cls,**kwds):
print('Foo subclass',cls,'with args',kwds)
class Bar(Foo):
pass
class Baz(Foo,foo=42):
pass
class Qux(Bar):
pass
class Florp(Bar,abc=123):
pass

View File

@ -0,0 +1,4 @@
Foo subclass <class '__main__.Bar'> with args {}
Foo subclass <class '__main__.Baz'> with args {'foo': 42}
Foo subclass <class '__main__.Qux'> with args {}
Foo subclass <class '__main__.Florp'> with args {'abc': 123}

View File

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

View File

@ -1,2 +1,2 @@
{'glossary': {'title': 'example glossary', 'GlossDiv': {'title': 'S', 'GlossList': {'GlossEntry': {'SortAs': 'SGML', 'Abbrev': 'ISO 8879:1986', 'Acronym': 'SGML', 'GlossTerm': 'Standard Generalized Markup Language', 'GlossSee': 'markup', 'ID': 'SGML', 'GlossDef': {'para': 'A meta-markup language, used to create markup languages such as DocBook.', 'GlossSeeAlso': ['GML', 'XML']}}}}}}
{'web-app': {'taglib': {'taglib-uri': 'cofax.tld', 'taglib-location': '/WEB-INF/tlds/cofax.tld'}, 'servlet': [{'servlet-class': 'org.cofax.cds.CDSServlet', 'init-param': {'templateProcessorClass': 'org.cofax.WysiwygTemplate', 'cachePagesStore': 100, 'searchEngineListTemplate': 'forSearchEnginesList.htm', 'searchEngineFileTemplate': 'forSearchEngines.htm', 'cachePackageTagsStore': 200, 'dataStoreUser': 'sa', 'dataStoreInitConns': 10, 'configGlossary:installationAt': 'Philadelphia, PA', 'cachePagesTrack': 200, 'dataStoreLogFile': '/usr/local/tomcat/logs/datastore.log', 'templateOverridePath': '', 'redirectionClass': 'org.cofax.SqlRedirection', 'cachePackageTagsTrack': 200, 'useDataStore': True, 'maxUrlLength': 500, 'dataStorePassword': 'dataStoreTestQuery', 'defaultFileTemplate': 'articleTemplate.htm', 'defaultListTemplate': 'listTemplate.htm', 'dataStoreConnUsageLimit': 100, 'templatePath': 'templates', 'useJSP': False, 'configGlossary:poweredBy': 'Cofax', 'dataStoreClass': 'org.cofax.SqlDataStore', 'dataStoreName': 'cofax', 'cacheTemplatesRefresh': 15, 'dataStoreDriver': 'com.microsoft.jdbc.sqlserver.SQLServerDriver', 'cachePagesDirtyRead': 10, 'configGlossary:adminEmail': 'ksm@pobox.com', 'dataStoreTestQuery': "SET NOCOUNT ON;select test='test';", 'cacheTemplatesStore': 50, 'templateLoaderClass': 'org.cofax.FilesTemplateLoader', 'configGlossary:staticPath': '/content/static', 'searchEngineRobotsDb': 'WEB-INF/robots.db', 'cacheTemplatesTrack': 100, 'dataStoreLogLevel': 'debug', 'dataStoreUrl': 'jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon', 'cachePagesRefresh': 10, 'configGlossary:poweredByIcon': '/images/cofax.gif', 'dataStoreMaxConns': 100, 'jspFileTemplate': 'articleTemplate.jsp', 'cachePackageTagsRefresh': 60, 'jspListTemplate': 'listTemplate.jsp'}, 'servlet-name': 'cofaxCDS'}, {'servlet-class': 'org.cofax.cds.EmailServlet', 'init-param': {'mailHostOverride': 'mail2', 'mailHost': 'mail1'}, 'servlet-name': 'cofaxEmail'}, {'servlet-class': 'org.cofax.cds.AdminServlet', 'servlet-name': 'cofaxAdmin'}, {'servlet-class': 'org.cofax.cds.FileServlet', 'servlet-name': 'fileServlet'}, {'servlet-class': 'org.cofax.cms.CofaxToolsServlet', 'init-param': {'logMaxSize': '', 'log': 1, 'removeTemplateCache': '/content/admin/remove?cache=templates&id=', 'dataLogMaxSize': '', 'lookInContext': 1, 'adminGroupID': 4, 'removePageCache': '/content/admin/remove?cache=pages&id=', 'dataLogLocation': '/usr/local/tomcat/logs/dataLog.log', 'betaServer': True, 'fileTransferFolder': '/usr/local/tomcat/webapps/content/fileTransferFolder', 'logLocation': '/usr/local/tomcat/logs/CofaxTools.log', 'dataLog': 1, 'templatePath': 'toolstemplates/'}, 'servlet-name': 'cofaxTools'}], 'servlet-mapping': {'cofaxCDS': '/', 'fileServlet': '/static/*', 'cofaxEmail': '/cofaxutil/aemail/*', 'cofaxTools': '/tools/*', 'cofaxAdmin': '/admin/*'}}}
{'glossary': {'title': 'example glossary', 'GlossDiv': {'title': 'S', 'GlossList': {'GlossEntry': {'ID': 'SGML', 'SortAs': 'SGML', 'GlossTerm': 'Standard Generalized Markup Language', 'Acronym': 'SGML', 'Abbrev': 'ISO 8879:1986', 'GlossDef': {'para': 'A meta-markup language, used to create markup languages such as DocBook.', 'GlossSeeAlso': ['GML', 'XML']}, 'GlossSee': 'markup'}}}}}
{'web-app': {'servlet': [{'servlet-name': 'cofaxCDS', 'servlet-class': 'org.cofax.cds.CDSServlet', 'init-param': {'configGlossary:installationAt': 'Philadelphia, PA', 'configGlossary:adminEmail': 'ksm@pobox.com', 'configGlossary:poweredBy': 'Cofax', 'configGlossary:poweredByIcon': '/images/cofax.gif', 'configGlossary:staticPath': '/content/static', 'templateProcessorClass': 'org.cofax.WysiwygTemplate', 'templateLoaderClass': 'org.cofax.FilesTemplateLoader', 'templatePath': 'templates', 'templateOverridePath': '', 'defaultListTemplate': 'listTemplate.htm', 'defaultFileTemplate': 'articleTemplate.htm', 'useJSP': False, 'jspListTemplate': 'listTemplate.jsp', 'jspFileTemplate': 'articleTemplate.jsp', 'cachePackageTagsTrack': 200, 'cachePackageTagsStore': 200, 'cachePackageTagsRefresh': 60, 'cacheTemplatesTrack': 100, 'cacheTemplatesStore': 50, 'cacheTemplatesRefresh': 15, 'cachePagesTrack': 200, 'cachePagesStore': 100, 'cachePagesRefresh': 10, 'cachePagesDirtyRead': 10, 'searchEngineListTemplate': 'forSearchEnginesList.htm', 'searchEngineFileTemplate': 'forSearchEngines.htm', 'searchEngineRobotsDb': 'WEB-INF/robots.db', 'useDataStore': True, 'dataStoreClass': 'org.cofax.SqlDataStore', 'redirectionClass': 'org.cofax.SqlRedirection', 'dataStoreName': 'cofax', 'dataStoreDriver': 'com.microsoft.jdbc.sqlserver.SQLServerDriver', 'dataStoreUrl': 'jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon', 'dataStoreUser': 'sa', 'dataStorePassword': 'dataStoreTestQuery', 'dataStoreTestQuery': "SET NOCOUNT ON;select test='test';", 'dataStoreLogFile': '/usr/local/tomcat/logs/datastore.log', 'dataStoreInitConns': 10, 'dataStoreMaxConns': 100, 'dataStoreConnUsageLimit': 100, 'dataStoreLogLevel': 'debug', 'maxUrlLength': 500}}, {'servlet-name': 'cofaxEmail', 'servlet-class': 'org.cofax.cds.EmailServlet', 'init-param': {'mailHost': 'mail1', 'mailHostOverride': 'mail2'}}, {'servlet-name': 'cofaxAdmin', 'servlet-class': 'org.cofax.cds.AdminServlet'}, {'servlet-name': 'fileServlet', 'servlet-class': 'org.cofax.cds.FileServlet'}, {'servlet-name': 'cofaxTools', 'servlet-class': 'org.cofax.cms.CofaxToolsServlet', 'init-param': {'templatePath': 'toolstemplates/', 'log': 1, 'logLocation': '/usr/local/tomcat/logs/CofaxTools.log', 'logMaxSize': '', 'dataLog': 1, 'dataLogLocation': '/usr/local/tomcat/logs/dataLog.log', 'dataLogMaxSize': '', 'removePageCache': '/content/admin/remove?cache=pages&id=', 'removeTemplateCache': '/content/admin/remove?cache=templates&id=', 'fileTransferFolder': '/usr/local/tomcat/webapps/content/fileTransferFolder', 'lookInContext': 1, 'adminGroupID': 4, 'betaServer': True}}], 'servlet-mapping': {'cofaxCDS': '/', 'cofaxEmail': '/cofaxutil/aemail/*', 'cofaxAdmin': '/admin/*', 'fileServlet': '/static/*', 'cofaxTools': '/tools/*'}, 'taglib': {'taglib-uri': 'cofax.tld', 'taglib-location': '/WEB-INF/tlds/cofax.tld'}}}

View File

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

View File

@ -0,0 +1,13 @@
try:
try:
print('try')
raise ValueError()
except 1/0:
print('bad: except body')
finally:
print(inner_error)
print('bad: after inner error')
except BaseException as e:
while e:
print(repr(e))
e = e.__context__

View File

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

View File

@ -0,0 +1,14 @@
class NonDataDescriptor:
def __get__(self, obj, objtype=None):
return 42
class Foo:
a = NonDataDescriptor()
def test(F):
print(F.a)
F.a = 7
print(F.a)
test(Foo())

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