@effekt-lang/effekt 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/effekt CHANGED
Binary file
@@ -4,6 +4,7 @@ extern io def commandLineArgs(): List[String] =
4
4
  js { js::commandLineArgs() }
5
5
  chez { chez::commandLineArgs() }
6
6
  llvm { llvm::commandLineArgs() }
7
+ vm { Nil() }
7
8
 
8
9
  namespace js {
9
10
  extern type Args // = Array[String]
@@ -16,6 +16,7 @@ extern global def allocate[T](size: Int): Array[T] =
16
16
  %z = call %Pos @c_array_new(%Int ${size})
17
17
  ret %Pos %z
18
18
  """
19
+ vm "array::allocate(Int)"
19
20
 
20
21
  /// Creates a new Array of size `size` filled with the value `init`
21
22
  def array[T](size: Int, init: T): Array[T] = {
@@ -45,6 +46,7 @@ extern pure def size[T](arr: Array[T]): Int =
45
46
  %z = call %Int @c_array_size(%Pos ${arr})
46
47
  ret %Int %z
47
48
  """
49
+ vm "array::size[T](Array[T])"
48
50
 
49
51
  /// Gets the element of the `arr` at given `index` in constant time.
50
52
  /// Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size)
@@ -57,6 +59,7 @@ extern global def unsafeGet[T](arr: Array[T], index: Int): T =
57
59
  %z = call %Pos @c_array_get(%Pos ${arr}, %Int ${index})
58
60
  ret %Pos %z
59
61
  """
62
+ vm "array::unsafeGet[T](Array[T], Int)"
60
63
 
61
64
  extern js """
62
65
  function array$set(arr, index, value) {
@@ -76,6 +79,7 @@ extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit =
76
79
  %z = call %Pos @c_array_set(%Pos ${arr}, %Int ${index}, %Pos ${value})
77
80
  ret %Pos %z
78
81
  """
82
+ vm "array::unsafeSet[T](Array[T], Int, T)"
79
83
 
80
84
 
81
85
 
@@ -45,6 +45,7 @@ extern def println(value: String): Unit =
45
45
  call void @c_io_println_String(%Pos ${value})
46
46
  ret %Pos zeroinitializer ; Unit
47
47
  """
48
+ vm "effekt::println(String)"
48
49
 
49
50
  def println(value: Int): Unit = println(value.show)
50
51
  def println(value: Unit): Unit = println(value.show)
@@ -59,6 +60,7 @@ extern pure def show(value: Int): String =
59
60
  %z = call %Pos @c_bytearray_show_Int(%Int ${value})
60
61
  ret %Pos %z
61
62
  """
63
+ vm "effekt::show(Int)"
62
64
 
63
65
  def show(value: Unit): String = "()"
64
66
 
@@ -69,6 +71,7 @@ extern pure def show(value: Double): String =
69
71
  %z = call %Pos @c_bytearray_show_Double(%Double ${value})
70
72
  ret %Pos %z
71
73
  """
74
+ vm "effekt::show(Double)"
72
75
 
73
76
  def show(value: String): String =
74
77
  value
@@ -83,6 +86,7 @@ extern pure def show(value: Char): String =
83
86
  %z = call %Pos @c_bytearray_show_Char(%Int ${value})
84
87
  ret %Pos %z
85
88
  """
89
+ vm "effekt::show(Char)"
86
90
 
87
91
  extern pure def show(value: Byte): String =
88
92
  js "'' + ${value}"
@@ -90,6 +94,7 @@ extern pure def show(value: Byte): String =
90
94
  %z = call %Pos @c_bytearray_show_Byte(i8 ${value})
91
95
  ret %Pos %z
92
96
  """
97
+ vm "effekt::show(Byte)"
93
98
 
94
99
  extern pure def genericShow[R](value: R): String =
95
100
  js "$effekt.show(${value})"
@@ -98,6 +103,7 @@ extern pure def genericShow[R](value: R): String =
98
103
  extern io def inspect[R](value: R): Unit =
99
104
  js { println(genericShow(value)) }
100
105
  chez { println(genericShow(value)) }
106
+ vm "effekt::inspect(Any)"
101
107
 
102
108
 
103
109
  // Strings
@@ -109,15 +115,16 @@ extern pure def infixConcat(s1: String, s2: String): String =
109
115
  %spz = call %Pos @c_bytearray_concatenate(%Pos ${s1}, %Pos ${s2})
110
116
  ret %Pos %spz
111
117
  """
118
+ vm "effekt::infixConcat(String, String)"
112
119
 
113
120
  extern pure def length(str: String): Int =
114
121
  js "${str}.length"
115
122
  chez "(string-length ${str})"
116
123
  llvm """
117
124
  %x = call %Int @c_bytearray_size(%Pos ${str})
118
- call void @erasePositive(%Pos ${str})
119
125
  ret %Int %x
120
126
  """
127
+ vm "effekt::length(String)"
121
128
 
122
129
  extern pure def unsafeSubstring(str: String, from: Int, to: Int): String =
123
130
  js "${str}.substring(${from}, ${to})"
@@ -126,6 +133,7 @@ extern pure def unsafeSubstring(str: String, from: Int, to: Int): String =
126
133
  %x = call %Pos @c_bytearray_substring(%Pos ${str}, i64 ${from}, i64 ${to})
127
134
  ret %Pos %x
128
135
  """
136
+ vm "effekt::substring(String, Int, Int)"
129
137
 
130
138
 
131
139
  // Side effecting ops
@@ -134,6 +142,7 @@ extern pure def unsafeSubstring(str: String, from: Int, to: Int): String =
134
142
  extern io def random(): Double =
135
143
  js "Math.random()"
136
144
  chez "(random 1.0)"
145
+ vm "effekt::random()"
137
146
 
138
147
  // References and state
139
148
  // ====================
@@ -193,8 +202,7 @@ def differsFrom[R](x: R, y: R): Bool =
193
202
 
194
203
  // TODO fix this in the pattern matching compiler
195
204
  extern pure def infixEq(x: Unit, y: Unit): Bool =
196
- js "true"
197
- chez "#t"
205
+ default { true }
198
206
 
199
207
  extern pure def infixEq(x: Int, y: Int): Bool =
200
208
  js "${x} === ${y}"
@@ -205,6 +213,7 @@ extern pure def infixEq(x: Int, y: Int): Bool =
205
213
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
206
214
  ret %Pos %adt_boolean
207
215
  """
216
+ vm "effekt::infixEq(Int, Int)"
208
217
 
209
218
  extern pure def infixNeq(x: Int, y: Int): Bool =
210
219
  js "${x} !== ${y}"
@@ -215,6 +224,7 @@ extern pure def infixNeq(x: Int, y: Int): Bool =
215
224
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
216
225
  ret %Pos %adt_boolean
217
226
  """
227
+ vm "effekt::infixNeq(Int, Int)"
218
228
 
219
229
  extern pure def infixEq(x: Char, y: Char): Bool =
220
230
  js "${x} === ${y}"
@@ -225,6 +235,7 @@ extern pure def infixEq(x: Char, y: Char): Bool =
225
235
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
226
236
  ret %Pos %adt_boolean
227
237
  """
238
+ vm "effekt::infixEq(Char, Char)"
228
239
 
229
240
  extern pure def infixNeq(x: Char, y: Char): Bool =
230
241
  js "${x} !== ${y}"
@@ -243,6 +254,7 @@ extern pure def infixEq(x: String, y: String): Bool =
243
254
  %res = call %Pos @c_bytearray_equal(%Pos ${x}, %Pos ${y})
244
255
  ret %Pos %res
245
256
  """
257
+ vm "effekt::infixEq(String, String)"
246
258
 
247
259
  def infixNeq(x: String, y: String): Bool = not(x == y)
248
260
 
@@ -257,6 +269,7 @@ extern pure def infixEq(x: Bool, y: Bool): Bool =
257
269
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
258
270
  ret %Pos %adt_boolean
259
271
  """
272
+ vm "effekt::infixEq(Bool, Bool)"
260
273
 
261
274
  extern pure def infixNeq(x: Bool, y: Bool): Bool =
262
275
  js "${x} !== ${y}"
@@ -277,67 +290,81 @@ extern pure def infixAdd(x: Int, y: Int): Int =
277
290
  js "(${x} + ${y})"
278
291
  chez "(+ ${x} ${y})"
279
292
  llvm "%z = add %Int ${x}, ${y} ret %Int %z"
293
+ vm "effekt::infixAdd(Int, Int)"
280
294
 
281
295
  extern pure def infixMul(x: Int, y: Int): Int =
282
296
  js "(${x} * ${y})"
283
297
  chez "(* ${x} ${y})"
284
298
  llvm "%z = mul %Int ${x}, ${y} ret %Int %z"
299
+ vm "effekt::infixMul(Int, Int)"
285
300
 
286
301
  extern pure def infixDiv(x: Int, y: Int): Int =
287
302
  js "Math.floor(${x} / ${y})"
288
303
  chez "(floor (/ ${x} ${y}))"
289
304
  llvm "%z = sdiv %Int ${x}, ${y} ret %Int %z"
305
+ vm "effekt::infixDiv(Int, Int)"
290
306
 
291
307
  extern pure def infixSub(x: Int, y: Int): Int =
292
308
  js "(${x} - ${y})"
293
309
  chez "(- ${x} ${y})"
294
310
  llvm "%z = sub %Int ${x}, ${y} ret %Int %z"
311
+ vm "effekt::infixSub(Int, Int)"
295
312
 
296
313
  extern pure def mod(x: Int, y: Int): Int =
297
314
  js "(${x} % ${y})"
298
315
  chez "(modulo ${x} ${y})"
299
316
  llvm "%z = srem %Int ${x}, ${y} ret %Int %z"
317
+ vm "effekt::mod(Int, Int)"
300
318
 
301
319
  extern pure def infixAdd(x: Double, y: Double): Double =
302
320
  js "(${x} + ${y})"
303
321
  chez "(+ ${x} ${y})"
304
322
  llvm "%z = fadd %Double ${x}, ${y} ret %Double %z"
323
+ vm "effekt::infixAdd(Double, Double)"
305
324
 
306
325
  extern pure def infixMul(x: Double, y: Double): Double =
307
326
  js "(${x} * ${y})"
308
327
  chez "(* ${x} ${y})"
309
328
  llvm "%z = fmul %Double ${x}, ${y} ret %Double %z"
329
+ vm "effekt::infixMul(Double, Double)"
310
330
 
311
331
  extern pure def infixSub(x: Double, y: Double): Double =
312
332
  js "(${x} - ${y})"
313
333
  chez "(- ${x} ${y})"
314
334
  llvm "%z = fsub %Double ${x}, ${y} ret %Double %z"
335
+ vm "effekt::infixSub(Double, Double)"
315
336
 
316
337
  extern pure def infixDiv(x: Double, y: Double): Double =
317
338
  js "(${x} / ${y})"
318
339
  chez "(/ ${x} ${y})"
319
340
  llvm "%z = fdiv %Double ${x}, ${y} ret %Double %z"
341
+ vm "effekt::infixDiv(Double, Double)"
320
342
 
321
343
  extern pure def cos(x: Double): Double =
322
344
  js "Math.cos(${x})"
323
345
  chez "(cos ${x})"
346
+ vm "effekt::cos(Double)"
324
347
 
325
348
  extern pure def sin(x: Double): Double =
326
349
  js "Math.sin(${x})"
327
350
  chez "(sin ${x})"
351
+ vm "effekt::sin(Double)"
328
352
 
329
353
  extern pure def atan(x: Double): Double =
330
354
  js "Math.atan(${x})"
331
355
  chez "(atan ${x})"
356
+ vm "effekt::atan(Double)"
332
357
 
333
358
  extern pure def tan(x: Double): Double =
334
359
  js "Math.tan(${x})"
335
360
  chez "(tan ${x})"
361
+ vm "effekt::tan(Double)"
336
362
 
337
363
  extern pure def sqrt(x: Double): Double =
338
364
  js "Math.sqrt(${x})"
339
365
  chez "(sqrt ${x})"
340
366
  llvm "%z = call %Double @llvm.sqrt.f64(double ${x}) ret %Double %z"
367
+ vm "effekt::sqrt(Double)"
341
368
 
342
369
  def square(x: Double): Double = x * x
343
370
 
@@ -353,6 +380,7 @@ def abs(n: Double): Double =
353
380
  extern pure def log(x: Double): Double =
354
381
  js "Math.log(${x})"
355
382
  chez "(log ${x})"
383
+ vm "effekt::log(Double)"
356
384
 
357
385
  extern pure def log1p(x: Double): Double =
358
386
  js "Math.log1p(${x})"
@@ -361,6 +389,7 @@ extern pure def log1p(x: Double): Double =
361
389
  extern pure def exp(x: Double): Double =
362
390
  js "Math.exp(${x})"
363
391
  chez "(exp ${x})"
392
+ vm "effekt::exp(Double)"
364
393
 
365
394
  def pow(base: Double, exponent: Int): Double = {
366
395
  def loop(base: Double, exponent: Int, acc: Double): Double = {
@@ -378,11 +407,13 @@ def pow(base: Double, exponent: Int): Double = {
378
407
  extern pure def pow(base: Double, exponent: Double): Double =
379
408
  js "Math.pow(${base}, ${exponent})"
380
409
  chez "(expt ${base} ${exponent})"
410
+ vm "effekt::pow(Double, Double)"
381
411
 
382
412
  // since we do not have "extern val", yet
383
413
  extern pure def _pi(): Double =
384
414
  js "Math.PI"
385
415
  chez "(* 4 (atan 1))"
416
+ vm "effekt::pi()"
386
417
 
387
418
  val PI: Double = _pi()
388
419
 
@@ -390,11 +421,14 @@ extern pure def toInt(d: Double): Int =
390
421
  js "Math.trunc(${d})"
391
422
  chez "(flonum->fixnum ${d})"
392
423
  llvm "%z = fptosi double ${d} to %Int ret %Int %z"
424
+ vm "effekt::toInt(Double)"
393
425
 
394
426
  extern pure def toDouble(d: Int): Double =
395
427
  js "${d}"
396
428
  chez "${d}"
397
429
  llvm "%z = sitofp i64 ${d} to double ret double %z"
430
+ vm "effekt::toDouble(Int)"
431
+
398
432
 
399
433
  extern pure def round(d: Double): Int =
400
434
  js "Math.round(${d})"
@@ -403,6 +437,7 @@ extern pure def round(d: Double): Int =
403
437
  %i = call %Double @llvm.round.f64(double ${d})
404
438
  %z = fptosi double %i to %Int ret %Int %z
405
439
  """
440
+ vm "effekt::round(Double)"
406
441
 
407
442
  def round(d: Double, digits: Int): Double = {
408
443
  val factor = pow(10.0, digits)
@@ -447,6 +482,7 @@ extern pure def infixLt(x: Int, y: Int): Bool =
447
482
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
448
483
  ret %Pos %adt_boolean
449
484
  """
485
+ vm "effekt::infixLt(Int, Int)"
450
486
 
451
487
  extern pure def infixLte(x: Int, y: Int): Bool =
452
488
  js "(${x} <= ${y})"
@@ -457,6 +493,7 @@ extern pure def infixLte(x: Int, y: Int): Bool =
457
493
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
458
494
  ret %Pos %adt_boolean
459
495
  """
496
+ vm "effekt::infixLte(Int, Int)"
460
497
 
461
498
  extern pure def infixGt(x: Int, y: Int): Bool =
462
499
  js "(${x} > ${y})"
@@ -467,6 +504,7 @@ extern pure def infixGt(x: Int, y: Int): Bool =
467
504
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
468
505
  ret %Pos %adt_boolean
469
506
  """
507
+ vm "effekt::infixGt(Int, Int)"
470
508
 
471
509
  extern pure def infixGte(x: Int, y: Int): Bool =
472
510
  js "(${x} >= ${y})"
@@ -477,14 +515,17 @@ extern pure def infixGte(x: Int, y: Int): Bool =
477
515
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
478
516
  ret %Pos %adt_boolean
479
517
  """
518
+ vm "effekt::infixGte(Int, Int)"
480
519
 
481
520
  extern pure def infixEq(x: Double, y: Double): Bool =
482
521
  js "${x} === ${y}"
483
522
  chez "(= ${x} ${y})"
523
+ vm "effekt::infixEq(Double, Double)"
484
524
 
485
525
  extern pure def infixNeq(x: Double, y: Double): Bool =
486
526
  js "${x} !== ${y}"
487
527
  chez "(not (= ${x} ${y}))"
528
+ vm "effekt::infixNeq(Double, Double)"
488
529
 
489
530
  extern pure def infixLt(x: Double, y: Double): Bool =
490
531
  js "(${x} < ${y})"
@@ -495,10 +536,12 @@ extern pure def infixLt(x: Double, y: Double): Bool =
495
536
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
496
537
  ret %Pos %adt_boolean
497
538
  """
539
+ vm "effekt::infixLt(Double, Double)"
498
540
 
499
541
  extern pure def infixLte(x: Double, y: Double): Bool =
500
542
  js "(${x} <= ${y})"
501
543
  chez "(<= ${x} ${y})"
544
+ vm "effekt::infixLte(Double, Double)"
502
545
 
503
546
  extern pure def infixGt(x: Double, y: Double): Bool =
504
547
  js "(${x} > ${y})"
@@ -509,10 +552,12 @@ extern pure def infixGt(x: Double, y: Double): Bool =
509
552
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
510
553
  ret %Pos %adt_boolean
511
554
  """
555
+ vm "effekt::infixGt(Double, Double)"
512
556
 
513
557
  extern pure def infixGte(x: Double, y: Double): Bool =
514
558
  js "(${x} >= ${y})"
515
559
  chez "(>= ${x} ${y})"
560
+ vm "effekt::infixGte(Double, Double)"
516
561
 
517
562
  // TODO do we really need those? if yes, move to string.effekt
518
563
  extern pure def infixLt(x: String, y: String): Bool =
@@ -543,6 +588,7 @@ extern pure def not(b: Bool): Bool =
543
588
  %adt_q = insertvalue %Pos zeroinitializer, i64 %q, 0
544
589
  ret %Pos %adt_q
545
590
  """
591
+ vm "effekt::not(Bool)"
546
592
 
547
593
  def infixOr { first: => Bool } { second: => Bool }: Bool =
548
594
  if (first()) true else second()
@@ -559,27 +605,32 @@ extern pure def bitwiseShl(x: Int, y: Int): Int =
559
605
  js "(${x} << ${y})"
560
606
  chez "(ash ${x} ${y})"
561
607
  llvm "%z = shl %Int ${x}, ${y} ret %Int %z"
608
+ vm "effekt::bitwiseShl(Int, Int)"
562
609
 
563
610
  /// Arithmetic right shift
564
611
  extern pure def bitwiseShr(x: Int, y: Int): Int =
565
612
  js "(${x} >> ${y})"
566
613
  chez "(ash ${x} (- ${y}))"
567
614
  llvm "%z = ashr %Int ${x}, ${y} ret %Int %z"
615
+ vm "effekt::bitwiseShr(Int, Int)"
568
616
 
569
617
  extern pure def bitwiseAnd(x: Int, y: Int): Int =
570
618
  js "(${x} & ${y})"
571
619
  chez "(logand ${x} ${y})"
572
620
  llvm "%z = and %Int ${x}, ${y} ret %Int %z"
621
+ vm "effekt::bitwiseAnd(Int, Int)"
573
622
 
574
623
  extern pure def bitwiseOr(x: Int, y: Int): Int =
575
624
  js "(${x} | ${y})"
576
625
  chez "(logior ${x} ${y})"
577
626
  llvm "%z = or %Int ${x}, ${y} ret %Int %z"
627
+ vm "effekt::bitwiseOr(Int, Int)"
578
628
 
579
629
  extern pure def bitwiseXor(x: Int, y: Int): Int =
580
630
  js "(${x} ^ ${y})"
581
631
  chez "(logxor ${x} ${y})"
582
632
  llvm "%z = xor %Int ${x}, ${y} ret %Int %z"
633
+ vm "effekt::bitwiseXor(Int, Int)"
583
634
 
584
635
 
585
636
  // Byte operations
@@ -198,6 +198,7 @@ namespace internal {
198
198
  ret void
199
199
  """
200
200
 
201
+ /// The buffer must be kept alive by using it after the call
201
202
  extern async def read(file: Int, buffer: ByteArray, offset: Int, size: Int, position: Int): Int =
202
203
  jsNode "$effekt.capture(callback => read(${file}, ${buffer}, ${offset}, ${size}, ${position}, callback))"
203
204
  llvm """
@@ -205,6 +206,7 @@ namespace internal {
205
206
  ret void
206
207
  """
207
208
 
209
+ /// The buffer must be kept alive by using it after the call
208
210
  extern async def write(file: Int, buffer: ByteArray, offset: Int, size: Int, position: Int): Int =
209
211
  jsNode "$effekt.capture(callback => write(${file}, ${buffer}, ${offset}, ${size}, ${position}, callback))"
210
212
  llvm """
@@ -16,7 +16,8 @@ extern async def spawn(task: Task[Unit]): Unit =
16
16
  js "$effekt.capture(k => { setTimeout(() => k($effekt.unit), 0); return $effekt.run(${task}) })"
17
17
  llvm """
18
18
  call void @c_yield(%Stack %stack)
19
- call void @run(%Neg ${task})
19
+ %unboxed = call ccc %Neg @unbox(%Pos ${task})
20
+ call void @run(%Neg %unboxed)
20
21
  ret void
21
22
  """
22
23
 
@@ -30,6 +30,7 @@ extern global def ref[T](init: T): Ref[T] =
30
30
  %z = call %Pos @c_ref_fresh(%Pos ${init})
31
31
  ret %Pos %z
32
32
  """
33
+ vm "ref::ref[T](T)"
33
34
 
34
35
  /// Gets the referenced element of the `ref` in constant time.
35
36
  extern global def get[T](ref: Ref[T]): T =
@@ -39,6 +40,7 @@ extern global def get[T](ref: Ref[T]): T =
39
40
  %z = call %Pos @c_ref_get(%Pos ${ref})
40
41
  ret %Pos %z
41
42
  """
43
+ vm "ref::get[T](Ref[T])"
42
44
 
43
45
  /// Sets the referenced element of the `ref` to `value` in constant time.
44
46
  extern global def set[T](ref: Ref[T], value: T): Unit =
@@ -48,3 +50,4 @@ extern global def set[T](ref: Ref[T], value: T): Unit =
48
50
  %z = call %Pos @c_ref_set(%Pos ${ref}, %Pos ${value})
49
51
  ret %Pos %z
50
52
  """
53
+ vm "ref::set[T](Ref[T], T)"
@@ -32,13 +32,16 @@ struct Pos c_array_new(const Int size) {
32
32
 
33
33
  Int c_array_size(const struct Pos arr) {
34
34
  uint64_t *sizePtr = arr.obj + sizeof(struct Header);
35
- return *sizePtr;
35
+ uint64_t size = *sizePtr;
36
+ erasePositive(arr);
37
+ return size;
36
38
  }
37
39
 
38
40
  struct Pos c_array_get(const struct Pos arr, const Int index) {
39
41
  struct Pos *dataPtr = arr.obj + sizeof(struct Header) + sizeof(uint64_t);
40
42
  struct Pos element = dataPtr[index];
41
43
  sharePositive(element);
44
+ erasePositive(arr);
42
45
  return element;
43
46
  }
44
47
 
@@ -47,6 +50,7 @@ struct Pos c_array_set(const struct Pos arr, const Int index, const struct Pos v
47
50
  struct Pos element = dataPtr[index];
48
51
  erasePositive(element);
49
52
  dataPtr[index] = value;
53
+ erasePositive(arr);
50
54
  return Unit;
51
55
  }
52
56
 
@@ -29,30 +29,34 @@ struct Pos c_bytearray_new(const Int size) {
29
29
  }
30
30
 
31
31
  Int c_bytearray_size(const struct Pos arr) {
32
+ erasePositive(arr);
32
33
  return arr.tag;
33
34
  }
34
35
 
35
- uint8_t* c_bytearray_data(const struct Pos arr) {
36
- return arr.obj + sizeof(struct Header);
37
- }
38
-
39
36
  Byte c_bytearray_get(const struct Pos arr, const Int index) {
40
37
  Byte *dataPtr = arr.obj + sizeof(struct Header);
41
38
  Byte element = dataPtr[index];
39
+ erasePositive(arr);
42
40
  return element;
43
41
  }
44
42
 
45
43
  struct Pos c_bytearray_set(const struct Pos arr, const Int index, const Byte value) {
46
44
  Byte *dataPtr = arr.obj + sizeof(struct Header);
47
45
  dataPtr[index] = value;
46
+ erasePositive(arr);
48
47
  return Unit;
49
48
  }
50
49
 
50
+ // Internal Operations
51
+
52
+ uint8_t* c_bytearray_data(const struct Pos arr) {
53
+ uint8_t *data = arr.obj + sizeof(struct Header);
54
+ return data;
55
+ }
56
+
51
57
  struct Pos c_bytearray_construct(const uint64_t n, const uint8_t *data) {
52
58
  struct Pos arr = c_bytearray_new(n);
53
-
54
59
  memcpy(c_bytearray_data(arr), data, n);
55
-
56
60
  return arr;
57
61
  }
58
62
 
@@ -66,7 +70,7 @@ struct Pos c_bytearray_from_nullterminated_string(const char *data) {
66
70
  }
67
71
 
68
72
  char* c_bytearray_into_nullterminated_string(const struct Pos arr) {
69
- uint64_t size = c_bytearray_size(arr);
73
+ uint64_t size = arr.tag;
70
74
 
71
75
  char* result = (char*)malloc(size + 1);
72
76
 
@@ -125,12 +129,14 @@ struct Pos c_bytearray_show_Double(const Double x) {
125
129
 
126
130
  // TODO do this in Effekt
127
131
  struct Pos c_bytearray_concatenate(const struct Pos left, const struct Pos right) {
128
- const struct Pos concatenated = c_bytearray_new(c_bytearray_size(left) + c_bytearray_size(right));
129
- for (int64_t j = 0; j < c_bytearray_size(concatenated); ++j)
132
+ uint64_t left_size = left.tag;
133
+ uint64_t right_size = right.tag;
134
+ const struct Pos concatenated = c_bytearray_new(left_size + right_size);
135
+ for (uint64_t j = 0; j < concatenated.tag; ++j)
130
136
  c_bytearray_data(concatenated)[j]
131
- = j < c_bytearray_size(left)
137
+ = j < left_size
132
138
  ? c_bytearray_data(left)[j]
133
- : c_bytearray_data(right)[j - c_bytearray_size(left)];
139
+ : c_bytearray_data(right)[j - left_size];
134
140
 
135
141
  erasePositive(left);
136
142
  erasePositive(right);
@@ -139,8 +145,8 @@ struct Pos c_bytearray_concatenate(const struct Pos left, const struct Pos right
139
145
 
140
146
  // TODO do this in Effekt
141
147
  struct Pos c_bytearray_equal(const struct Pos left, const struct Pos right) {
142
- uint64_t left_size = c_bytearray_size(left);
143
- uint64_t right_size = c_bytearray_size(right);
148
+ uint64_t left_size = left.tag;
149
+ uint64_t right_size = right.tag;
144
150
  if (left_size != right_size) {
145
151
  erasePositive(left);
146
152
  erasePositive(right);
@@ -161,7 +167,7 @@ struct Pos c_bytearray_equal(const struct Pos left, const struct Pos right) {
161
167
  // TODO deprecate
162
168
  struct Pos c_bytearray_substring(const struct Pos str, uint64_t start, uint64_t end) {
163
169
  const struct Pos substr = c_bytearray_new(end - start);
164
- for (int64_t j = 0; j < c_bytearray_size(substr); ++j) {
170
+ for (uint64_t j = 0; j < substr.tag; ++j) {
165
171
  c_bytearray_data(substr)[j] = c_bytearray_data(str)[start+j];
166
172
  }
167
173
  erasePositive(str);
@@ -174,27 +180,27 @@ uint32_t c_bytearray_character_at(const struct Pos str, const uint64_t index) {
174
180
  uint8_t first_byte = bytes[index];
175
181
  uint32_t character = 0;
176
182
 
177
- uint32_t length = c_bytearray_size(str);
183
+ uint32_t size = str.tag;
178
184
 
179
185
  if (first_byte < 0x80) {
180
186
  // Single-byte character (0xxxxxxx)
181
187
  character = first_byte;
182
188
  } else if ((first_byte & 0xE0) == 0xC0) {
183
189
  // Two-byte character (110xxxxx 10xxxxxx)
184
- if (index + 1 < length) {
190
+ if (index + 1 < size) {
185
191
  character = ((first_byte & 0x1F) << 6) |
186
192
  (bytes[index + 1] & 0x3F);
187
193
  }
188
194
  } else if ((first_byte & 0xF0) == 0xE0) {
189
195
  // Three-byte character (1110xxxx 10xxxxxx 10xxxxxx)
190
- if (index + 2 < length) {
196
+ if (index + 2 < size) {
191
197
  character = ((first_byte & 0x0F) << 12) |
192
198
  ((bytes[index + 1] & 0x3F) << 6) |
193
199
  (bytes[index + 2] & 0x3F);
194
200
  }
195
201
  } else if ((first_byte & 0xF8) == 0xF0) {
196
202
  // Four-byte character (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx)
197
- if (index + 3 < length) {
203
+ if (index + 3 < size) {
198
204
  character = ((first_byte & 0x07) << 18) |
199
205
  ((bytes[index + 1] & 0x3F) << 12) |
200
206
  ((bytes[index + 2] & 0x3F) << 6) |
@@ -20,7 +20,7 @@ void c_io_println_Double(const Double x) {
20
20
  }
21
21
 
22
22
  void c_io_println_String(String text) {
23
- for (int64_t j = 0; j < c_bytearray_size(text); ++j)
23
+ for (uint64_t j = 0; j < text.tag; ++j)
24
24
  putchar(c_bytearray_data(text)[j]);
25
25
  erasePositive(text);
26
26
  putchar('\n');
@@ -126,8 +126,8 @@ void c_fs_open(String path, struct Pos mode, Stack stack) {
126
126
  void c_fs_read(Int file, struct Pos buffer, Int offset, Int size, Int position, Stack stack) {
127
127
 
128
128
  uv_buf_t buf = uv_buf_init((char*)(c_bytearray_data(buffer) + offset), size);
129
- // erasePositive(buffer);
130
- // TODO we should erase the buffer but abort if this was the last reference
129
+ erasePositive(buffer);
130
+ // TODO panic if this was the last reference
131
131
 
132
132
  uv_fs_t* request = malloc(sizeof(uv_fs_t));
133
133
  request->data = stack;
@@ -144,8 +144,8 @@ void c_fs_read(Int file, struct Pos buffer, Int offset, Int size, Int position,
144
144
  void c_fs_write(Int file, struct Pos buffer, Int offset, Int size, Int position, Stack stack) {
145
145
 
146
146
  uv_buf_t buf = uv_buf_init((char*)(c_bytearray_data(buffer) + offset), size);
147
- // erasePositive(buffer);
148
- // TODO we should erase the buffer but abort if this was the last reference
147
+ erasePositive(buffer);
148
+ // TODO panic if this was the last reference
149
149
 
150
150
  uv_fs_t* request = malloc(sizeof(uv_fs_t));
151
151
  request->data = stack;
@@ -9,7 +9,6 @@
9
9
 
10
10
  #define DEBUG_REFCOUNT (false)
11
11
 
12
- #include "sanity.c"
13
12
  #include "types.c"
14
13
  #include "bytearray.c"
15
14
  #include "io.c"
@@ -31,6 +31,7 @@ struct Pos c_ref_get(const struct Pos ref) {
31
31
  struct Pos *fieldPtr = ref.obj + sizeof(struct Header);
32
32
  struct Pos element = *fieldPtr;
33
33
  sharePositive(element);
34
+ erasePositive(ref);
34
35
  return element;
35
36
  }
36
37
 
@@ -39,6 +40,7 @@ struct Pos c_ref_set(const struct Pos ref, const struct Pos value) {
39
40
  struct Pos element = *fieldPtr;
40
41
  erasePositive(element);
41
42
  *fieldPtr = value;
43
+ erasePositive(ref);
42
44
  return Unit;
43
45
  }
44
46
 
@@ -114,6 +114,26 @@ declare void @exit(i64)
114
114
  declare void @llvm.assume(i1)
115
115
 
116
116
 
117
+ ; Boxing (externs functions, hence ccc)
118
+ define ccc %Pos @box(%Neg %input) {
119
+ %vtable = extractvalue %Neg %input, 0
120
+ %heap_obj = extractvalue %Neg %input, 1
121
+ %vtable_as_int = ptrtoint ptr %vtable to i64
122
+ %pos_result = insertvalue %Pos undef, i64 %vtable_as_int, 0
123
+ %pos_result_with_heap = insertvalue %Pos %pos_result, ptr %heap_obj, 1
124
+ ret %Pos %pos_result_with_heap
125
+ }
126
+
127
+ define ccc %Neg @unbox(%Pos %input) {
128
+ %tag = extractvalue %Pos %input, 0
129
+ %heap_obj = extractvalue %Pos %input, 1
130
+ %vtable = inttoptr i64 %tag to ptr
131
+ %neg_result = insertvalue %Neg undef, ptr %vtable, 0
132
+ %neg_result_with_heap = insertvalue %Neg %neg_result, ptr %heap_obj, 1
133
+ ret %Neg %neg_result_with_heap
134
+ }
135
+
136
+
117
137
  ; Prompts
118
138
 
119
139
  define private %Prompt @currentPrompt(%Stack %stack) {