@effekt-lang/effekt 0.54.0 → 0.55.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 +0 -0
- package/libraries/common/list.effekt +16 -0
- package/libraries/common/process.effekt +99 -0
- package/libraries/common/stream.effekt +109 -4
- package/libraries/llvm/io.c +195 -0
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +2 -2
- package/licenses/mit license - mit-license.html +91 -90
- package/licenses/the bsd license - bsd-license.html +92 -91
- package/licenses/the mit license - mit.html +91 -90
- package/package.json +1 -1
package/bin/effekt
CHANGED
|
Binary file
|
|
@@ -944,6 +944,22 @@ def each[A](list: List[A]): Unit / emit[A] =
|
|
|
944
944
|
each(tail)
|
|
945
945
|
}
|
|
946
946
|
|
|
947
|
+
/// Push iterator that emits all the tails (suffixes) of the given `list`.
|
|
948
|
+
///
|
|
949
|
+
/// Examples:
|
|
950
|
+
/// ```effekt
|
|
951
|
+
/// > list::collect[List[Int]] { [1, 2, 3].tails }
|
|
952
|
+
/// [[1, 2, 3], [2, 3], [3], []]
|
|
953
|
+
///
|
|
954
|
+
/// > list::collect[List[Int]] { [].tails }
|
|
955
|
+
/// [[]]
|
|
956
|
+
/// ```
|
|
957
|
+
def tails[A](list: List[A]): Unit / emit[List[A]] =
|
|
958
|
+
list match {
|
|
959
|
+
case Nil() => do emit(Nil())
|
|
960
|
+
case Cons(head, tail) => do emit(list); tails(tail)
|
|
961
|
+
}
|
|
962
|
+
|
|
947
963
|
def feed[T, R](list: List[T]) { reader: () => R / read[T] }: R = {
|
|
948
964
|
var l = list
|
|
949
965
|
try {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
module process
|
|
2
|
+
import array
|
|
2
3
|
|
|
3
4
|
extern def exit(errorCode: Int) at io: Nothing =
|
|
4
5
|
js "(function() { process.exit(${errorCode}) })()"
|
|
@@ -7,3 +8,101 @@ extern def exit(errorCode: Int) at io: Nothing =
|
|
|
7
8
|
ret %Pos zeroinitializer
|
|
8
9
|
"""
|
|
9
10
|
chez "(exit ${errorCode})"
|
|
11
|
+
|
|
12
|
+
// Subprocesses
|
|
13
|
+
// ------------
|
|
14
|
+
|
|
15
|
+
extern jsNode """
|
|
16
|
+
const { spawn } = require('node:child_process');
|
|
17
|
+
"""
|
|
18
|
+
extern llvm """
|
|
19
|
+
declare %Pos @c_spawn_options_default()
|
|
20
|
+
declare %Pos @c_spawn_options_on_stdout(%Pos, %Pos)
|
|
21
|
+
declare %Pos @c_spawn_options_on_stderr(%Pos, %Pos)
|
|
22
|
+
declare %Pos @c_spawn_options_pipe_stdin(%Pos, %Pos)
|
|
23
|
+
declare %Pos @c_write_stream(%Pos, %Pos)
|
|
24
|
+
declare %Pos @c_close_stream(%Pos)
|
|
25
|
+
declare %Pos @c_spawn(%Pos, %Pos, %Pos)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
extern type SpawnOptions
|
|
29
|
+
extern def default() at {}: SpawnOptions =
|
|
30
|
+
jsNode """{ stdio: [0,1,2], onSpawn: (p) => {} }"""
|
|
31
|
+
llvm """
|
|
32
|
+
%opts = call %Pos @c_spawn_options_default()
|
|
33
|
+
ret %Pos %opts
|
|
34
|
+
"""
|
|
35
|
+
extern def onStdout(opts: SpawnOptions, callback: String => Unit at {io, global}) at {}: SpawnOptions =
|
|
36
|
+
jsNode """(function() {
|
|
37
|
+
let old = ${opts};
|
|
38
|
+
old.stdio[1] = 'pipe';
|
|
39
|
+
let oldSpawn = old.onSpawn;
|
|
40
|
+
old.onSpawn = function(p) {
|
|
41
|
+
oldSpawn(p);
|
|
42
|
+
p.stdout.on('data', (chunk) => {
|
|
43
|
+
$effekt.runToplevel((ks, k) => (${callback})(chunk, ks, k));
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
return old; })()"""
|
|
47
|
+
llvm """
|
|
48
|
+
%opts = call %Pos @c_spawn_options_on_stdout(%Pos ${opts}, %Pos ${callback})
|
|
49
|
+
ret %Pos %opts
|
|
50
|
+
"""
|
|
51
|
+
extern def onStderr(opts: SpawnOptions, callback: String => Unit at {io, global}) at {}: SpawnOptions =
|
|
52
|
+
jsNode """(function() {
|
|
53
|
+
let old = ${opts};
|
|
54
|
+
old.stdio[2] = 'pipe';
|
|
55
|
+
let oldSpawn = old.onSpawn;
|
|
56
|
+
old.onSpawn = function(p) {
|
|
57
|
+
oldSpawn(p);
|
|
58
|
+
p.stderr.on('data', (chunk) => {
|
|
59
|
+
$effekt.runToplevel((ks, k) => (${callback})(chunk, ks, k));
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
return old; })()"""
|
|
63
|
+
llvm """
|
|
64
|
+
%opts = call %Pos @c_spawn_options_on_stderr(%Pos ${opts}, %Pos ${callback})
|
|
65
|
+
ret %Pos %opts
|
|
66
|
+
"""
|
|
67
|
+
extern type WritableStream
|
|
68
|
+
extern def withStdin(opts: SpawnOptions, callback: WritableStream => Unit at {io, global}) at {}: SpawnOptions =
|
|
69
|
+
jsNode """(function () {
|
|
70
|
+
let old = ${opts};
|
|
71
|
+
old.stdio[0] = 'pipe'
|
|
72
|
+
let oldSpawn = old.onSpawn;
|
|
73
|
+
old.onSpawn = function(p) {
|
|
74
|
+
oldSpawn(p);
|
|
75
|
+
p.on('spawn', () => {
|
|
76
|
+
$effekt.runToplevel((ks, k) => (${callback})(p.stdin, ks, k));
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
return old;
|
|
80
|
+
})()"""
|
|
81
|
+
llvm """
|
|
82
|
+
%opts = call %Pos @c_spawn_options_pipe_stdin(%Pos ${opts}, %Pos ${callback})
|
|
83
|
+
ret %Pos %opts
|
|
84
|
+
"""
|
|
85
|
+
extern def write(to: WritableStream, s: String) at io: Unit =
|
|
86
|
+
jsNode """${to}.write(${s})"""
|
|
87
|
+
llvm """
|
|
88
|
+
call void @c_write_stream(%Pos ${to}, %Pos ${s})
|
|
89
|
+
ret %Pos zeroinitializer
|
|
90
|
+
"""
|
|
91
|
+
extern def close(to: WritableStream) at io: Unit =
|
|
92
|
+
jsNode """${to}.end()"""
|
|
93
|
+
llvm """
|
|
94
|
+
call void @c_close_stream(%Pos ${to})
|
|
95
|
+
ret %Pos zeroinitializer
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
extern def spawn(cmd: String, args: Array[String], options: SpawnOptions) at async: Int =
|
|
99
|
+
jsNode """$effekt.capture(k => {
|
|
100
|
+
let p = spawn(${cmd}, ${args}, ${options});
|
|
101
|
+
${options}.onSpawn(p);
|
|
102
|
+
p.on('close', (exitcode, sig) => { k(exitcode) });
|
|
103
|
+
return p;
|
|
104
|
+
})"""
|
|
105
|
+
llvm """
|
|
106
|
+
call void @c_spawn(%Pos ${cmd}, %Pos ${args}, %Pos ${options}, %Stack %stack)
|
|
107
|
+
ret void
|
|
108
|
+
"""
|
|
@@ -2,6 +2,7 @@ module stream
|
|
|
2
2
|
|
|
3
3
|
import effekt
|
|
4
4
|
import option
|
|
5
|
+
import exception
|
|
5
6
|
|
|
6
7
|
// Effects
|
|
7
8
|
// -------
|
|
@@ -128,6 +129,26 @@ def iterate[A](initial: A) { step: A => A }: Unit / emit[A] = {
|
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
|
|
132
|
+
/// Re-emit from the `stream` as long as the `predicate` holds.
|
|
133
|
+
/// Once the predicate fails, the stream ends.
|
|
134
|
+
///
|
|
135
|
+
/// Examples:
|
|
136
|
+
/// ```effekt
|
|
137
|
+
/// > list::collect[Int] { takeWhile[Int] { x => x < 3 } { [1, 2, 3, 4, 1].each } }
|
|
138
|
+
/// [1, 2]
|
|
139
|
+
///
|
|
140
|
+
/// > list::collect[Int] { takeWhile[Int] { x => x < 10 } { [1, 2, 3].each } }
|
|
141
|
+
/// [1, 2, 3]
|
|
142
|
+
///
|
|
143
|
+
/// > list::collect[Int] { takeWhile[Int] { x => x < 0 } { [1, 2, 3].each } }
|
|
144
|
+
/// []
|
|
145
|
+
/// ```
|
|
146
|
+
def takeWhile[A] { predicate: A => Bool } { stream: () => Unit / emit[A] }: Unit / emit[A] =
|
|
147
|
+
try { stream() } with emit[A] {
|
|
148
|
+
case value and predicate(value) => do emit(value); resume(())
|
|
149
|
+
case _ => () // end the stream
|
|
150
|
+
}
|
|
151
|
+
|
|
131
152
|
|
|
132
153
|
def sum { stream: () => Unit / emit[Int] }: Int =
|
|
133
154
|
returning::sum[Unit]{stream}.second
|
|
@@ -135,6 +156,71 @@ def sum { stream: () => Unit / emit[Int] }: Int =
|
|
|
135
156
|
def product { stream: () => Unit / emit[Int] }: Int =
|
|
136
157
|
returning::product[Unit]{stream}.second
|
|
137
158
|
|
|
159
|
+
/// Returns true if all elements in the stream satisfy the given predicate,
|
|
160
|
+
/// false otherwise. Short-circuits as soon as a non-matching element is found.
|
|
161
|
+
///
|
|
162
|
+
/// Examples:
|
|
163
|
+
/// ```effekt
|
|
164
|
+
/// > all[Int] { x => x > 0 } { [1, 2, 3].each }
|
|
165
|
+
/// true
|
|
166
|
+
///
|
|
167
|
+
/// > all[Int] { x => x < 3 } { [1, 2, 3, 4].each }
|
|
168
|
+
/// false
|
|
169
|
+
///
|
|
170
|
+
/// > all[Bool] { x => x } { [false, true, true].each }
|
|
171
|
+
/// false
|
|
172
|
+
///
|
|
173
|
+
/// > all[Int] { x => x >= 0 } { () } // empty stream
|
|
174
|
+
/// true
|
|
175
|
+
/// ```
|
|
176
|
+
def all[A] { cond: A => Bool } { stream: => Unit / emit[A] }: Bool =
|
|
177
|
+
try { stream(); true } with emit[A] {
|
|
178
|
+
case value and not(cond(value)) => false
|
|
179
|
+
case _ => resume(())
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/// Returns true if any element in the stream satisfies the given predicate,
|
|
183
|
+
/// false otherwise. Short-circuits as soon as a matching element is found.
|
|
184
|
+
///
|
|
185
|
+
/// Examples:
|
|
186
|
+
/// ```effekt
|
|
187
|
+
/// > any[Int] { x => x > 0 } { [-2, -1, 0, 1, 2].each }
|
|
188
|
+
/// true
|
|
189
|
+
///
|
|
190
|
+
/// > any[Int] { x => x > 10 } { [1, 2, 3, 4].each }
|
|
191
|
+
/// false
|
|
192
|
+
///
|
|
193
|
+
/// > any[Bool] { x => x } { [false, true, false].each }
|
|
194
|
+
/// true
|
|
195
|
+
///
|
|
196
|
+
/// > any[Int] { x => x == 0 } { () } // empty stream
|
|
197
|
+
/// false
|
|
198
|
+
/// ```
|
|
199
|
+
def any[A] { cond: A => Bool } { stream: => Unit / emit[A] }: Bool =
|
|
200
|
+
try { stream(); false } with emit[A] {
|
|
201
|
+
case value and cond(value) => true
|
|
202
|
+
case _ => resume(())
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/// Count the number of emitted values that satisfy the given predicate.
|
|
206
|
+
///
|
|
207
|
+
/// Examples:
|
|
208
|
+
/// ```
|
|
209
|
+
/// > countIf[Int] { x => x > 0 } { [2, -1, 0, 1, -2].each }
|
|
210
|
+
/// 2
|
|
211
|
+
///
|
|
212
|
+
/// > countIf[Bool] { x => x } { [false, false, true, false].each }
|
|
213
|
+
/// 1
|
|
214
|
+
/// ```
|
|
215
|
+
def countIf[A] { shouldCount: A => Bool } { stream: () => Unit / emit[A] }: Int = {
|
|
216
|
+
var count = 0
|
|
217
|
+
for {stream} {
|
|
218
|
+
case x and shouldCount(x) => count = count + 1
|
|
219
|
+
case _ => ()
|
|
220
|
+
}
|
|
221
|
+
count
|
|
222
|
+
}
|
|
223
|
+
|
|
138
224
|
def source[A] { stream: () => Unit / emit[A] } { reader: () => Unit / read[A] }: Unit =
|
|
139
225
|
returning::source[A, Unit]{stream}{reader}
|
|
140
226
|
|
|
@@ -177,9 +263,9 @@ namespace internal {
|
|
|
177
263
|
|
|
178
264
|
/// Use cons to handle prod, but also emit to the outside.
|
|
179
265
|
/// The outside controls iteration, i.e., if cons aborts, the rest of prod will still be emitted.
|
|
180
|
-
///
|
|
266
|
+
///
|
|
181
267
|
/// Starts by executing cons. Will stop cons during execution if the outside stops consuming.
|
|
182
|
-
///
|
|
268
|
+
///
|
|
183
269
|
/// Example, printing all values consumed by the outside:
|
|
184
270
|
///
|
|
185
271
|
/// with teeing{ {s} => for{s}{ e => println(e) } }
|
|
@@ -215,9 +301,9 @@ def teeing[A]{ cons: { => Unit / emit[A] } => Unit }{ prod: => Unit / emit[A] }:
|
|
|
215
301
|
}
|
|
216
302
|
|
|
217
303
|
/// Binds a `teeing`-like function in the body, stopping the inner producer once all consumers in tees are done consuming.
|
|
218
|
-
///
|
|
304
|
+
///
|
|
219
305
|
/// Example of use, equivalent to `tee[A]{cns1}{cns2}{prd}`:
|
|
220
|
-
///
|
|
306
|
+
///
|
|
221
307
|
/// manyTee[A] { {tee} =>
|
|
222
308
|
/// with tee{cns1}
|
|
223
309
|
/// with tee{cns2}
|
|
@@ -253,6 +339,25 @@ def tee[A]{ cons1: { => Unit / emit[A] } => Unit }{ cons2: { => Unit / emit[A] }
|
|
|
253
339
|
}
|
|
254
340
|
}
|
|
255
341
|
|
|
342
|
+
/// Return exactly the very first element of the given stream
|
|
343
|
+
/// or raise MissingValue if no elements are emitted.
|
|
344
|
+
///
|
|
345
|
+
/// Examples:
|
|
346
|
+
/// ```effekt
|
|
347
|
+
/// > first[Int] { [1, 2, 3].each }
|
|
348
|
+
/// 1
|
|
349
|
+
/// > first[Bool] { do emit(true) }
|
|
350
|
+
/// true
|
|
351
|
+
/// > first[String] { () } // empty stream
|
|
352
|
+
/// <Exception MissingValue: code in first did not emit any values>
|
|
353
|
+
/// ```
|
|
354
|
+
def first[A] { body: => Unit / emit[A] }: A / Exception[MissingValue] =
|
|
355
|
+
try {
|
|
356
|
+
body()
|
|
357
|
+
val r: A = do raise[MissingValue](MissingValue(), "code in first did not emit any values")
|
|
358
|
+
r
|
|
359
|
+
} with emit[A] { a => a }
|
|
360
|
+
|
|
256
361
|
namespace returning {
|
|
257
362
|
|
|
258
363
|
/// Canonical handler of push streams that performs `action` for every
|
package/libraries/llvm/io.c
CHANGED
|
@@ -627,4 +627,199 @@ void c_signal_notify(struct Pos signal, struct Pos value, Stack stack) {
|
|
|
627
627
|
}
|
|
628
628
|
}
|
|
629
629
|
|
|
630
|
+
// Subprocesses
|
|
631
|
+
// ------------
|
|
632
|
+
|
|
633
|
+
struct Pos c_spawn_options_default() {
|
|
634
|
+
uv_process_options_t* options = (uv_process_options_t*)malloc(sizeof(uv_process_options_t));
|
|
635
|
+
memset(options, 0, sizeof(uv_process_options_t));
|
|
636
|
+
uv_stdio_container_t* stdio = (uv_stdio_container_t*)malloc(3*sizeof(uv_stdio_container_t));
|
|
637
|
+
stdio[0].flags = UV_INHERIT_FD;
|
|
638
|
+
stdio[0].data.fd = 0;
|
|
639
|
+
stdio[1].flags = UV_INHERIT_FD;
|
|
640
|
+
stdio[1].data.fd = 1;
|
|
641
|
+
stdio[2].flags = UV_INHERIT_FD;
|
|
642
|
+
stdio[2].data.fd = 2;
|
|
643
|
+
options->stdio = stdio;
|
|
644
|
+
options->stdio_count = 3;
|
|
645
|
+
return (struct Pos) { .tag = 0, .obj = options, };
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
static void subproc_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
|
|
649
|
+
(void)handle;
|
|
650
|
+
buf->base = malloc(suggested_size);
|
|
651
|
+
buf->len = suggested_size;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
typedef struct {
|
|
655
|
+
struct Pos handler;
|
|
656
|
+
} subproc_stream_cb_closure_t;
|
|
657
|
+
void subproc_stream_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
|
|
658
|
+
subproc_stream_cb_closure_t* clos = (subproc_stream_cb_closure_t*)(stream->data);
|
|
659
|
+
if(nread >= 0) {
|
|
660
|
+
struct Pos chunk = c_bytearray_construct(nread, (uint8_t*)(buf->base));
|
|
661
|
+
if (buf->base) free(buf->base);
|
|
662
|
+
run_Pos(clos->handler, chunk);
|
|
663
|
+
} else {
|
|
664
|
+
uv_read_stop(stream);
|
|
665
|
+
erasePositive(clos->handler);
|
|
666
|
+
free(clos);
|
|
667
|
+
if (buf->base) free(buf->base);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
struct Pos subproc_options_on_stream(struct Pos opts, size_t id, uv_stdio_flags flags, struct Pos callback) {
|
|
671
|
+
uv_process_options_t* options = (uv_process_options_t*)opts.obj;
|
|
672
|
+
|
|
673
|
+
options->stdio[id].flags = UV_CREATE_PIPE | flags;
|
|
674
|
+
uv_pipe_t* pipe = (uv_pipe_t*)malloc(sizeof(uv_pipe_t));
|
|
675
|
+
|
|
676
|
+
uv_pipe_init(uv_default_loop(), pipe, 1);
|
|
677
|
+
options->stdio[id].data.stream = (uv_stream_t*)pipe;
|
|
678
|
+
|
|
679
|
+
subproc_stream_cb_closure_t* clos = (subproc_stream_cb_closure_t*)malloc(sizeof(subproc_stream_cb_closure_t));
|
|
680
|
+
clos->handler = callback;
|
|
681
|
+
pipe->data = clos;
|
|
682
|
+
|
|
683
|
+
return opts;
|
|
684
|
+
}
|
|
685
|
+
struct Pos c_spawn_options_on_stdout(struct Pos opts, struct Pos callback) {
|
|
686
|
+
return subproc_options_on_stream(opts, 1, UV_WRITABLE_PIPE, callback);
|
|
687
|
+
}
|
|
688
|
+
struct Pos c_spawn_options_on_stderr(struct Pos opts, struct Pos callback) {
|
|
689
|
+
return subproc_options_on_stream(opts, 2, UV_WRITABLE_PIPE, callback);
|
|
690
|
+
}
|
|
691
|
+
struct Pos c_spawn_options_pipe_stdin(struct Pos opts, struct Pos callback) {
|
|
692
|
+
return subproc_options_on_stream(opts, 0, UV_READABLE_PIPE, callback);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
typedef struct {
|
|
697
|
+
char** args;
|
|
698
|
+
Stack k;
|
|
699
|
+
uv_process_options_t* opts;
|
|
700
|
+
} subproc_proc_data_t;
|
|
701
|
+
void c_close_stream_callback_exit(uv_handle_t* req) {
|
|
702
|
+
free(req);
|
|
703
|
+
}
|
|
704
|
+
void subproc_on_close(uv_handle_t* handle) {
|
|
705
|
+
subproc_proc_data_t* pd = (subproc_proc_data_t*)((uv_process_t*)handle)->data;
|
|
706
|
+
uv_process_options_t* opts = (uv_process_options_t*)(pd->opts);
|
|
707
|
+
if(opts->stdio[0].flags & UV_CREATE_PIPE){
|
|
708
|
+
uv_close((uv_handle_t*)(opts->stdio[0].data.stream), c_close_stream_callback_exit);
|
|
709
|
+
}
|
|
710
|
+
if(opts->stdio[1].flags & UV_CREATE_PIPE){
|
|
711
|
+
uv_close((uv_handle_t*)(opts->stdio[1].data.stream), c_close_stream_callback_exit);
|
|
712
|
+
}
|
|
713
|
+
if(opts->stdio[2].flags & UV_CREATE_PIPE){
|
|
714
|
+
uv_close((uv_handle_t*)(opts->stdio[2].data.stream), c_close_stream_callback_exit);
|
|
715
|
+
}
|
|
716
|
+
// TODO shutdown pipes for stdio
|
|
717
|
+
free(opts->stdio);
|
|
718
|
+
free(opts);
|
|
719
|
+
free(pd);
|
|
720
|
+
free(handle);
|
|
721
|
+
}
|
|
722
|
+
void subproc_on_exit(uv_process_t* proc, int64_t exit_status, int term_signal) {
|
|
723
|
+
(void)term_signal; (void)exit_status;
|
|
724
|
+
subproc_proc_data_t* pd = (subproc_proc_data_t*)proc->data;
|
|
725
|
+
if (pd->args) {
|
|
726
|
+
for(int i = 0; pd->args[i] != NULL; i++) {
|
|
727
|
+
free(pd->args[i]);
|
|
728
|
+
}
|
|
729
|
+
free(pd->args);
|
|
730
|
+
}
|
|
731
|
+
Stack k = pd->k;
|
|
732
|
+
uv_close((uv_handle_t*)proc, subproc_on_close);
|
|
733
|
+
resume_Int(k, exit_status);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
void c_close_stream_callback(uv_shutdown_t* req, int status) {
|
|
737
|
+
if(status != 0){
|
|
738
|
+
// TODO error handling
|
|
739
|
+
}
|
|
740
|
+
free(req);
|
|
741
|
+
}
|
|
742
|
+
void c_close_stream(struct Pos stream) {
|
|
743
|
+
uv_stream_t* str = (uv_stream_t*)stream.obj;
|
|
744
|
+
uv_shutdown_t* req = (uv_shutdown_t*)malloc(sizeof(uv_shutdown_t));
|
|
745
|
+
uv_shutdown(req, str, c_close_stream_callback);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
typedef struct {
|
|
749
|
+
struct Pos buffer;
|
|
750
|
+
uv_buf_t buf;
|
|
751
|
+
} subproc_write_req_data_t;
|
|
752
|
+
void c_write_stream_callback(uv_write_t* req, int status) {
|
|
753
|
+
if(status != 0){
|
|
754
|
+
// TODO error handling
|
|
755
|
+
}
|
|
756
|
+
subproc_write_req_data_t* data = (subproc_write_req_data_t*)(req->data);
|
|
757
|
+
erasePositive(data->buffer);
|
|
758
|
+
free(data);
|
|
759
|
+
free(req);
|
|
760
|
+
}
|
|
761
|
+
void c_write_stream(struct Pos stream, struct Pos buffer) {
|
|
762
|
+
uv_stream_t* str = (uv_stream_t*)stream.obj;
|
|
763
|
+
uv_write_t* req = (uv_write_t*)malloc(sizeof(uv_write_t));
|
|
764
|
+
memset(req, 0, sizeof(uv_write_t));
|
|
765
|
+
subproc_write_req_data_t* data = (subproc_write_req_data_t*)malloc(sizeof(subproc_write_req_data_t));
|
|
766
|
+
data->buffer = buffer;
|
|
767
|
+
uv_buf_t buf = uv_buf_init((char*)(c_bytearray_data(buffer)), buffer.tag);
|
|
768
|
+
req->data = data;
|
|
769
|
+
data->buf = buf;
|
|
770
|
+
uv_write(req, str, &(data->buf), 1, c_write_stream_callback);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
void c_spawn(struct Pos cmd, struct Pos args, struct Pos options, Stack stack) {
|
|
774
|
+
uv_process_options_t* opts = (uv_process_options_t*)options.obj;
|
|
775
|
+
uv_process_t* proc = (uv_process_t*)malloc(sizeof(uv_process_t));
|
|
776
|
+
|
|
777
|
+
// command
|
|
778
|
+
char* cmd_s = c_bytearray_into_nullterminated_string(cmd);
|
|
779
|
+
erasePositive(cmd);
|
|
780
|
+
opts->file = cmd_s;
|
|
781
|
+
|
|
782
|
+
// args
|
|
783
|
+
int _argc = (int)((uint64_t*)args.obj)[2];
|
|
784
|
+
char** _args = (char**)malloc((2 + _argc) * sizeof(char*));
|
|
785
|
+
struct Pos* _argv = (struct Pos*)(((uint64_t*)args.obj) + 3);
|
|
786
|
+
_args[0] = cmd_s;
|
|
787
|
+
for(int i = 0; i < _argc; i++) {
|
|
788
|
+
_args[i + 1] = c_bytearray_into_nullterminated_string(_argv[i]);
|
|
789
|
+
}
|
|
790
|
+
erasePositive(args);
|
|
791
|
+
_args[_argc + 1] = NULL;
|
|
792
|
+
opts->args = _args;
|
|
793
|
+
// callback to free _args
|
|
794
|
+
opts->exit_cb = subproc_on_exit;
|
|
795
|
+
subproc_proc_data_t* pd = (subproc_proc_data_t*)malloc(sizeof(subproc_proc_data_t));
|
|
796
|
+
pd->args = _args;
|
|
797
|
+
pd->k = stack;
|
|
798
|
+
proc->data = pd;
|
|
799
|
+
|
|
800
|
+
// spawn process
|
|
801
|
+
int err = uv_spawn(uv_default_loop(), proc, opts);
|
|
802
|
+
|
|
803
|
+
if(opts->stdio[0].flags & UV_CREATE_PIPE) {
|
|
804
|
+
uv_stream_t* stream = (uv_stream_t*)(opts->stdio[0].data.stream);
|
|
805
|
+
subproc_stream_cb_closure_t* clos = (subproc_stream_cb_closure_t*)(stream->data);
|
|
806
|
+
struct Pos str = (struct Pos) { .tag = 0, .obj = stream, };
|
|
807
|
+
run_Pos(clos->handler, str);
|
|
808
|
+
erasePositive(clos->handler);
|
|
809
|
+
free(clos);
|
|
810
|
+
}
|
|
811
|
+
if(opts->stdio[1].flags & UV_CREATE_PIPE)
|
|
812
|
+
uv_read_start((uv_stream_t*)(opts->stdio[1].data.stream), subproc_alloc_cb, subproc_stream_cb);
|
|
813
|
+
if(opts->stdio[2].flags & UV_CREATE_PIPE)
|
|
814
|
+
uv_read_start((uv_stream_t*)(opts->stdio[2].data.stream), subproc_alloc_cb, subproc_stream_cb);
|
|
815
|
+
pd->opts = opts;
|
|
816
|
+
|
|
817
|
+
erasePositive(options);
|
|
818
|
+
if(err) {
|
|
819
|
+
printf("%s\n", uv_strerror(err));
|
|
820
|
+
free(_args);
|
|
821
|
+
free(proc);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
630
825
|
#endif
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Eclipse Public License 2.0 (EPL) | The Eclipse Foundation</title>
|
|
2
|
-
<meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/og-image.jpg"><meta name=twitter:image content="https://www.eclipse.org/images/og-image.jpg"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.144.2"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=
|
|
2
|
+
<meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/og-image.jpg"><meta name=twitter:image content="https://www.eclipse.org/images/og-image.jpg"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.144.2"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1765134958"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a href=#main class=skip-link>Skip to content</a><div class=eclipsefdn-featured-story-banner data-publish-target=eclipse_org></div><header class="header-wrapper header-wrapper" id=header><div class="navigation-bar dark"><div class=container><div class=navigation-bar-inner><div class=navigation-bar-left><a class="focus-highlight focus-inverse" href=/><img class=navigation-bar-brand src=https://www.eclipse.org/eclipse.org-common/themes/solstice/public/images/logo/eclipse-foundation-white-orange.svg alt="Eclipse Foundation"></a></div><nav class="navigation-bar-nav hidden-xs hidden-sm"><ul><li><a href=# data-target=join-us-menu>Join us</a></li><li><a href=# data-target=what-we-do-menu>What we do</a></li><li><a href=# data-target=resources-menu>Resources</a></li><li><a href=# data-target=about-us-menu>About us</a></li></ul></nav><div class=navigation-bar-right><div class="navigation-bar-controls hidden-xs hidden-sm"><ul><li class=dropdown><a class="dropdown-toggle link-unstyled focus-highlight" tabindex=0 id=search-dropdown-toggle data-toggle=dropdown href=# aria-label=Search><i class="fa-solid fa-magnifying-glass" aria-hidden=true></i></a><form class="search-bar dropdown-menu dropdown-menu-right" aria-labelledby=search-dropdown-toggle action=https://www.eclipse.org/home/search/ method=get><input class=search-bar-input name=q placeholder=Search>
|
|
3
3
|
<button class="btn btn-link" type=submit>
|
|
4
4
|
<i class="fa-solid fa-arrow-right"></i></button></form></li><li class=dropdown><a class="dropdown-toggle focus-highlight" id=user-menu href=# data-toggle=dropdown aria-haspopup=true aria-expanded=false tabindex=0><i class="fa-regular fa-user" aria-hidden=true></i></a><ul class="dropdown-menu dropdown-menu-right" aria-labelledby=user-menu><li><a href=https://accounts.eclipse.org/user><i class="fa-solid fa-user margin-right-10" aria-hidden=true></i>
|
|
5
5
|
View my account</a></li><li><a href=https://accounts.eclipse.org/user/edit><i class="fa-solid fa-edit margin-right-10" aria-hidden=true></i>
|
|
@@ -39,4 +39,4 @@ Manage cookies</a></li></ul></li></ul></div><div class="navigation-bar-ctas hidd
|
|
|
39
39
|
<i class="fa-brands fa-youtube fa-stack-1x fa-inverse" aria-hidden=true></i></span></a></li><li><a href=https://www.linkedin.com/company/eclipse-foundation aria-label=LinkedIn><span class=fa-stack><i class="fa-solid fa-circle fa-stack-2x" aria-hidden=true></i>
|
|
40
40
|
<i class="fa-brands fa-linkedin-in fa-stack-1x fa-inverse" aria-hidden=true></i></span></a></li></ul></section><section class=newsletter-section><p class="subheading text-tertiary">Stay up to date</p><h2>Subscribe to our newsletter</h2><form class="newsletter-form margin-top-40" id=mc-embedded-subscribe-form action="https://eclipse.us6.list-manage.com/subscribe/post?u=eaf9e1f06f194eadc66788a85&id=e7538485cd&f_id=00f9c2e1f0" method=post novalidate target=_blank><div class=text-field-outlined><input name=EMAIL type=email placeholder="Your email">
|
|
41
41
|
<button class=newsletter-form-submit type=submit name=subscribe id=mc-embedded-subscribe aria-label=Submit>
|
|
42
|
-
<i class="fa-solid fa-arrow-right" aria-hidden=true></i></button></div></form></section><section class=footer-bottom-section><img class="img-responsive logo" src=https://www.eclipse.org/eclipse.org-common/themes/solstice/public/images/logo/eclipse-foundation-white.svg alt="Eclipse Foundation"><div class=legal-information><p>Copyright © Eclipse Foundation AISBL. All rights reserved.</p><ul class=legal-links><li><a href=https://www.eclipse.org/legal/privacy/>Privacy policy</a></li><li><a href=https://www.eclipse.org/legal/terms-of-use/>Terms of use</a></li><li><a href=https://www.eclipse.org/legal/compliance/>Compliance</a></li><li><a href=https://www.eclipse.org/legal/>Legal</a></li></ul></div></section></div></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=
|
|
42
|
+
<i class="fa-solid fa-arrow-right" aria-hidden=true></i></button></div></form></section><section class=footer-bottom-section><img class="img-responsive logo" src=https://www.eclipse.org/eclipse.org-common/themes/solstice/public/images/logo/eclipse-foundation-white.svg alt="Eclipse Foundation"><div class=legal-information><p>Copyright © Eclipse Foundation AISBL. All rights reserved.</p><ul class=legal-links><li><a href=https://www.eclipse.org/legal/privacy/>Privacy policy</a></li><li><a href=https://www.eclipse.org/legal/terms-of-use/>Terms of use</a></li><li><a href=https://www.eclipse.org/legal/compliance/>Compliance</a></li><li><a href=https://www.eclipse.org/legal/>Legal</a></li></ul></div></section></div></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1765134958"></script><script>(function(){})(jQuery,document)</script></div></body></html>
|