value.c
1 #include <limits.h>
2 #include <string.h>
3 #include <kuroko/memory.h>
4 #include <kuroko/value.h>
5 #include <kuroko/object.h>
6 #include <kuroko/vm.h>
7 #include <kuroko/util.h>
8 
9 #include "opcode_enum.h"
10 
12  array->values = NULL;
13  array->capacity = 0;
14  array->count = 0;
15 }
16 
18  if (array->capacity < array->count + 1) {
19  int old = array->capacity;
20  array->capacity = GROW_CAPACITY(old);
21  array->values = GROW_ARRAY(KrkValue, array->values, old, array->capacity);
22  }
23 
24  array->values[array->count] = value;
25  array->count++;
26 }
27 
29  FREE_ARRAY(KrkValue, array->values, array->capacity);
30  krk_initValueArray(array);
31 }
32 
33 void krk_printValue(FILE * f, KrkValue printable) {
34  KrkClass * type = krk_getType(printable);
35  if (type->_tostr) {
36  krk_push(printable);
37  printable = krk_callDirect(type->_tostr, 1);
38  if (!IS_STRING(printable)) return;
39  fprintf(f, "%s", AS_CSTRING(printable));
40  } else if (type->_reprer) {
41  krk_push(printable);
42  printable = krk_callDirect(type->_reprer, 1);
43  if (!IS_STRING(printable)) return;
44  fprintf(f, "%s", AS_CSTRING(printable));
45  } else {
46  fprintf(f, "%s", krk_typeName(printable));
47  }
48 }
49 
50 #define STRING_DEBUG_TRUNCATE 50
51 
52 void krk_printValueSafe(FILE * f, KrkValue printable) {
53  if (!IS_OBJECT(printable)) {
54  switch (KRK_VAL_TYPE(printable)) {
55  case KRK_VAL_INTEGER: fprintf(f, PRIkrk_int, AS_INTEGER(printable)); break;
56  case KRK_VAL_BOOLEAN: fprintf(f, "%s", AS_BOOLEAN(printable) ? "True" : "False"); break;
57  case KRK_VAL_NONE: fprintf(f, "None"); break;
58  case KRK_VAL_HANDLER:
59  switch (AS_HANDLER_TYPE(printable)) {
60  case OP_PUSH_TRY: fprintf(f, "{try->%d}", (int)AS_HANDLER_TARGET(printable)); break;
61  case OP_PUSH_WITH: fprintf(f, "{with->%d}", (int)AS_HANDLER_TARGET(printable)); break;
62  case OP_RAISE: fprintf(f, "{raise<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
63  case OP_FILTER_EXCEPT: fprintf(f, "{except<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
64  case OP_BEGIN_FINALLY: fprintf(f, "{finally<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
65  case OP_RETURN: fprintf(f, "{return<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
66  case OP_END_FINALLY: fprintf(f, "{end<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
67  case OP_EXIT_LOOP: fprintf(f, "{exit<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
68  case OP_RAISE_FROM: fprintf(f, "{reraise<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
69  }
70  break;
71  case KRK_VAL_KWARGS: {
72  if (AS_INTEGER(printable) == KWARGS_SINGLE) {
73  fprintf(f, "{unpack single}");
74  } else if (AS_INTEGER(printable) == KWARGS_LIST) {
75  fprintf(f, "{unpack list}");
76  } else if (AS_INTEGER(printable) == KWARGS_DICT) {
77  fprintf(f, "{unpack dict}");
78  } else if (AS_INTEGER(printable) == KWARGS_NIL) {
79  fprintf(f, "{unpack nil}");
80  } else if (AS_INTEGER(printable) == KWARGS_UNSET) {
81  fprintf(f, "{unset default}");
82  } else {
83  fprintf(f, "{sentinel=" PRIkrk_int "}",AS_INTEGER(printable));
84  }
85  break;
86  }
87  default:
88 #ifndef KRK_NO_FLOAT
89  if (IS_FLOATING(printable)) fprintf(f, "%.16g", AS_FLOATING(printable));
90 #endif
91  break;
92  }
93  } else if (IS_STRING(printable)) {
94  fprintf(f, "'");
95  /*
96  * Print at most STRING_DEBUG_TRUNCATE characters, as bytes, escaping anything not ASCII.
97  * See also str.__repr__ which does something similar with escape sequences, but this
98  * is a dumber, safer, and slightly faster approach.
99  */
100  for (size_t c = 0; c < AS_STRING(printable)->length && c < STRING_DEBUG_TRUNCATE; ++c) {
101  unsigned char byte = (unsigned char)AS_CSTRING(printable)[c];
102  switch (byte) {
103  case '\\': fprintf(f, "\\\\"); break;
104  case '\n': fprintf(f, "\\n"); break;
105  case '\r': fprintf(f, "\\r"); break;
106  case '\'': fprintf(f, "\\'"); break;
107  default: {
108  if (byte < ' ' || byte > '~') {
109  fprintf(f, "\\x%02x", byte);
110  } else {
111  fprintf(f, "%c", byte);
112  }
113  break;
114  }
115  }
116  }
117  if (AS_STRING(printable)->length > STRING_DEBUG_TRUNCATE) {
118  fprintf(f,"...");
119  }
120  fprintf(f,"'");
121  } else {
122  switch (AS_OBJECT(printable)->type) {
123  case KRK_OBJ_CODEOBJECT: fprintf(f, "<codeobject %s>", AS_codeobject(printable)->name ? AS_codeobject(printable)->name->chars : "?"); break;
124  case KRK_OBJ_CLASS: fprintf(f, "<class %s>", AS_CLASS(printable)->name ? AS_CLASS(printable)->name->chars : "?"); break;
125  case KRK_OBJ_INSTANCE: fprintf(f, "<instance of %s>", AS_INSTANCE(printable)->_class->name->chars); break;
126  case KRK_OBJ_NATIVE: fprintf(f, "<nativefn %s>", ((KrkNative*)AS_OBJECT(printable))->name); break;
127  case KRK_OBJ_CLOSURE: fprintf(f, "<function %s>", AS_CLOSURE(printable)->function->name->chars); break;
128  case KRK_OBJ_BYTES: fprintf(f, "<bytes of len %ld>", (long)AS_BYTES(printable)->length); break;
129  case KRK_OBJ_TUPLE: {
130  fprintf(f, "(");
131  for (size_t i = 0; i < AS_TUPLE(printable)->values.count; ++i) {
132  krk_printValueSafe(f, AS_TUPLE(printable)->values.values[i]);
133  if (i + 1 != AS_TUPLE(printable)->values.count) {
134  fprintf(f, ",");
135  }
136  }
137  fprintf(f, ")");
138  } break;
139  case KRK_OBJ_BOUND_METHOD: fprintf(f, "<method %s>",
140  AS_BOUND_METHOD(printable)->method ? (
141  AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_CLOSURE ? ((KrkClosure*)AS_BOUND_METHOD(printable)->method)->function->name->chars :
142  (AS_BOUND_METHOD(printable)->method->type == KRK_OBJ_NATIVE ? ((KrkNative*)AS_BOUND_METHOD(printable)->method)->name : "(unknown)")) : "(corrupt bound method)"); break;
143  default: fprintf(f, "<%s>", krk_typeName(printable)); break;
144  }
145  }
146 }
147 
152  return a == b;
153 }
154 
155 static inline int _krk_method_equivalence(KrkValue a, KrkValue b) {
156  KrkClass * type = krk_getType(a);
157  if (likely(type && type->_eq)) {
158  krk_push(a);
159  krk_push(b);
160  KrkValue result = krk_callDirect(type->_eq,2);
161  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 0;
162  if (IS_BOOLEAN(result)) return AS_BOOLEAN(result);
163  if (!IS_NOTIMPL(result)) return !krk_isFalsey(result);
164  }
165 
166  type = krk_getType(b);
167  if (type && type->_eq) {
168  krk_push(b);
169  krk_push(a);
170  KrkValue result = krk_callDirect(type->_eq,2);
171  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 0;
172  if (IS_BOOLEAN(result)) return AS_BOOLEAN(result);
173  if (!IS_NOTIMPL(result)) return !krk_isFalsey(result);
174  }
175 
176  return 0;
177 }
178 
179 static inline int _krk_same_type_equivalence(uint16_t valtype, KrkValue a, KrkValue b) {
180  switch (valtype) {
181  case KRK_VAL_BOOLEAN:
182  case KRK_VAL_INTEGER:
183  case KRK_VAL_NONE:
184  case KRK_VAL_NOTIMPL:
185  case KRK_VAL_KWARGS:
186  case KRK_VAL_HANDLER:
187  return a == b;
188  case KRK_VAL_OBJECT:
189  default:
190  return _krk_method_equivalence(a,b);
191  }
192 }
193 
194 static inline int _krk_same_type_equivalence_b(uint16_t valtype, KrkValue a, KrkValue b) {
195  switch (valtype) {
196  case KRK_VAL_BOOLEAN:
197  case KRK_VAL_INTEGER:
198  case KRK_VAL_NONE:
199  case KRK_VAL_NOTIMPL:
200  case KRK_VAL_KWARGS:
201  case KRK_VAL_HANDLER:
202  return 0;
203  case KRK_VAL_OBJECT:
204  default:
205  return _krk_method_equivalence(a,b);
206  }
207 }
208 
209 static inline int _krk_diff_type_equivalence(uint16_t val_a, uint16_t val_b, KrkValue a, KrkValue b) {
210  /* We do not want to let KWARGS leak to anything needs to, eg., examine types. */
211  if (val_b == KRK_VAL_KWARGS || val_a == KRK_VAL_KWARGS) return 0;
212 
213  /* Fall back to methods */
214  return _krk_method_equivalence(a,b);
215 }
216 
217 __attribute__((hot))
219  if (a == b) return 1;
220  uint16_t val_a = KRK_VAL_TYPE(a);
221  uint16_t val_b = KRK_VAL_TYPE(b);
222  return (val_a == val_b)
223  ? _krk_same_type_equivalence_b(val_a, a, b)
224  : _krk_diff_type_equivalence(val_a, val_b, a, b);
225 }
226 
227 __attribute__((hot))
229  uint16_t val_a = KRK_VAL_TYPE(a);
230  uint16_t val_b = KRK_VAL_TYPE(b);
231  return (val_a == val_b)
232  ? _krk_same_type_equivalence(val_a,a,b)
233  : _krk_diff_type_equivalence(val_a,val_b,a,b);
234 }
Functions for dealing with garbage collection and memory allocation.
Struct definitions for core object types.
Type object.
Definition: object.h:189
KrkObj * _tostr
__str__ Called to produce a string from an instance
Definition: object.h:204
KrkObj * _reprer
__repr__ Called to create a reproducible string representation of an instance
Definition: object.h:203
KrkObj * _eq
__eq__ Implementation for equality check (==)
Definition: object.h:207
Function object.
Definition: object.h:169
Managed binding to a C function.
Definition: object.h:283
int flags
Definition: vm.h:174
Flexible vector of stack references.
Definition: value.h:70
size_t capacity
Definition: value.h:71
KrkValue * values
Definition: value.h:73
void krk_initValueArray(KrkValueArray *array)
Initialize a value array.
Definition: value.c:11
void krk_freeValueArray(KrkValueArray *array)
Release relesources used by a value array.
Definition: value.c:28
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Definition: value.c:17
size_t count
Definition: value.h:72
Stack reference or primative value.
const char * krk_typeName(KrkValue value)
Get the name of the type of a value.
Definition: vm.c:1023
int krk_valuesEqual(KrkValue a, KrkValue b)
Compare two values for equality.
void krk_printValue(FILE *f, KrkValue value)
Print a string representation of a value.
Definition: value.c:33
int krk_valuesSame(KrkValue a, KrkValue b)
Compare two values by identity.
Definition: value.c:151
KrkClass * krk_getType(KrkValue value)
Get the class representing a value.
Definition: vm.c:275
int krk_valuesSameOrEqual(KrkValue a, KrkValue b)
Compare two values by identity, then by equality.
void krk_printValueSafe(FILE *f, KrkValue value)
Print a value without calling the VM.
Definition: value.c:52
int krk_isFalsey(KrkValue value)
Determine the truth of a value.
Definition: vm.c:852
Utilities for creating native bindings.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:157
KrkValue krk_callDirect(KrkObj *callable, int argCount)
Call a closure or native function with argCount arguments.
Definition: vm.c:771