@effekt-lang/effekt 0.13.0 → 0.15.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.
@@ -19,24 +19,13 @@ effect read[A](): A / stop
19
19
  /// Signal from a producer to a consumer that there are no further values.
20
20
  effect stop(): Nothing
21
21
 
22
- /// Canonical handler of push streams that performs `action` for every
23
- /// value emitted by `stream`.
24
- def for[A, R] { stream: () => R / emit[A] } { action: A => Unit }: R =
25
- try {
26
- stream()
27
- } with emit[A] { value =>
28
- resume(action(value))
29
- }
30
-
31
22
  /// Like `for[A, R]`, but ignores the result of the stream, and consequently
32
23
  /// works for any type. Use this to annotate the type of stream elements
33
24
  /// `A` without having to also annotate `R`.
34
25
  ///
35
26
  /// e.g. for[Int] { prog() } { el => println(el) }
36
- def for[A] { stream: () => Any / emit[A] } { action: A => Unit }: Unit = {
37
- for[A, Any]{stream}{action}
38
- ()
39
- }
27
+ def for[A] { stream: () => Unit / emit[A] } { action: A => Unit }: Unit =
28
+ returning::for[A, Unit]{stream}{action}
40
29
 
41
30
  /// Turns a `list` into a producer of a push stream
42
31
  /// by emitting each contained value left-to-right.
@@ -81,20 +70,13 @@ def each(bytes: ByteArray): Unit / emit[Byte] = {
81
70
  // not seq
82
71
 
83
72
 
84
- def boundary[R] { program: () => R / stop }: Option[R] =
85
- try {
86
- Some(program())
87
- } with stop {
88
- None()
89
- }
90
-
91
- def boundary { program: () => Any / stop }: Unit = {
92
- boundary[Any]{program}
73
+ def boundary { program: () => Unit / stop }: Unit = {
74
+ returning::boundary[Unit]{program}
93
75
  ()
94
76
  }
95
77
 
96
78
  /// Run `program` forever until `stop` is thrown.
97
- def exhaustively { program: () => Any / stop }: Unit =
79
+ def exhaustively { program: () => Unit / stop }: Unit =
98
80
  try {
99
81
  def go(): Unit = {
100
82
  program()
@@ -105,6 +87,24 @@ def exhaustively { program: () => Any / stop }: Unit =
105
87
  ()
106
88
  }
107
89
 
90
+ def many[A] { action: () => A / stop }: Unit / emit[A] =
91
+ exhaustively { do emit(action()) }
92
+
93
+ def some[A] { action: () => A / stop }: Unit / { emit[A], stop } = {
94
+ do emit(action())
95
+ many { action() }
96
+ }
97
+
98
+ def optionally { program: () => Unit / stop }: Bool =
99
+ returning::optionally[Unit]{program}.isDefined
100
+
101
+ def attempt[R] { program: () => R / stop } { fallback: () => R }: R =
102
+ try {
103
+ program()
104
+ } with stop {
105
+ fallback()
106
+ }
107
+
108
108
 
109
109
  /// In Effekt lower bounds are inclusive and upper bounds are exclusive
110
110
  record Indexed[A](index: Int, value: A)
@@ -123,39 +123,13 @@ def rangeFrom(lower: Int): Unit / emit[Int] = {
123
123
  rangeFrom(lower + 1)
124
124
  }
125
125
 
126
+ def index[A] { stream: () => Unit / emit[A] }: Unit / emit[Indexed[A]] =
127
+ returning::index[A, Unit]{stream}
126
128
 
127
- def index[A, R] { stream: () => R / emit[A] }: R / emit[Indexed[A]] = {
128
- var i = 0;
129
- try {
130
- stream()
131
- } with emit[A] { v =>
132
- val c = i;
133
- i = c + 1;
134
- resume(do emit(Indexed(c, v)))
135
- }
136
- }
137
129
 
138
130
  /// If `number` is zero or negative it does nothing
139
- def limit[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop } = {
140
- if (number <= 0) do stop();
141
- var i = 1;
142
- try {
143
- stream()
144
- } with emit[A] { v =>
145
- if (i < number) {
146
- i = i + 1;
147
- resume(do emit(v))
148
- } else {
149
- do stop()
150
- }
151
- }
152
- }
153
-
154
- /// If `number` is zero or negative it does nothing
155
- def limit[A](number: Int) { stream: () => Any / emit[A] }: Unit / emit[A] =
156
- boundary {
157
- limit[A, Any](number){stream}
158
- }
131
+ def limit[A](number: Int) { stream: () => Unit / emit[A] }: Unit / {emit[A], stop} =
132
+ returning::limit[A, Unit](number){stream}
159
133
 
160
134
 
161
135
  /// If `number` is zero or negative it does nothing
@@ -166,61 +140,17 @@ def replicate[A](number: Int) { action: () => A }: Unit / emit[A] =
166
140
  }
167
141
 
168
142
 
169
- def sum[R] { stream : () => R / emit[Int] }: (R, Int) = {
170
- var s = 0;
171
- try {
172
- (stream(), s)
173
- } with emit[Int] { v =>
174
- s = s + v;
175
- resume(())
176
- }
177
- }
143
+ def sum { stream : () => Unit / emit[Int] }: Int =
144
+ returning::sum[Unit]{stream}.second
178
145
 
179
- def sum { stream : () => Any / emit[Int] }: Int =
180
- sum[Any]{stream}.second
146
+ def collectList[A] { stream: () => Unit / emit[A] }: List[A] =
147
+ returning::collectList[A, Unit]{stream}.second
181
148
 
182
- def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) =
183
- try {
184
- (stream(), Nil())
185
- } with emit[A] { (v) =>
186
- val (r, vs) = resume(());
187
- (r, Cons(v, vs))
188
- }
189
-
190
- def collectList[A] { stream: () => Any / emit[A] }: List[A] =
191
- collectList[A, Any]{stream}.second
192
-
193
- def collectArray[A, R] { stream: () => R / emit[A] }: (R, Array[A]) = {
194
- var i = 0
195
- var a = array::allocate(1)
196
- try {
197
- (stream(), a.resize(i))
198
- } with emit[A] { (v) =>
199
- if (i >= a.size) { a = a.resize(2 * a.size) }
200
- a.unsafeSet(i, v)
201
- i = i + 1
202
- resume(())
203
- }
204
- }
205
-
206
- def collectArray[A] { stream: () => Any / emit[A] }: Array[A] =
207
- collectArray[A, Any]{stream}.second
208
-
209
- def collectBytes[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
210
- var i = 0
211
- var a = bytearray::allocate(1)
212
- try {
213
- (stream(), a.resize(i))
214
- } with emit[Byte] { (v) =>
215
- if (i >= a.size) { a = a.resize(2 * a.size) }
216
- a.unsafeSet(i, v)
217
- i = i + 1
218
- resume(())
219
- }
220
- }
149
+ def collectArray[A] { stream: () => Unit / emit[A] }: Array[A] =
150
+ returning::collectArray[A, Unit]{stream}.second
221
151
 
222
- def collectBytes { stream: () => Any / emit[Byte] }: ByteArray =
223
- collectBytes[Any]{stream}.second
152
+ def collectBytes { stream: () => Unit / emit[Byte] }: ByteArray =
153
+ returning::collectBytes[Unit]{stream}.second
224
154
 
225
155
  def feed[T, R](list: List[T]) { reader: () => R / read[T] }: R = {
226
156
  var l = list
@@ -272,34 +202,12 @@ def feed[R](bytes: ByteArray) { reader: () => R / read[Byte] }: R = {
272
202
  }
273
203
  }
274
204
 
275
- def source[A, R] { stream: () => Any / emit[A] } { reader: () => R / read[A] }: R = {
276
- var next = box { None() }
277
- next = box {
278
- try {
279
- stream()
280
- None()
281
- } with emit[A] { (v) =>
282
- next = box { resume(()) }
283
- Some(v)
284
- }
285
- }
286
- try {
287
- reader()
288
- } with read[A] {
289
- resume {
290
- next().getOrElse { do stop() }
291
- }
292
- }
293
- }
294
-
295
- def source[A] { stream: () => Any / emit[A] } { reader: () => Any / read[A] }: Unit = {
296
- source[A, Any]{stream}{reader}
297
- ()
298
- }
205
+ def source[A] { stream: () => Unit / emit[A] } { reader: () => Unit / read[A] }: Unit =
206
+ returning::source[A, Unit]{stream}{reader}
299
207
 
300
208
  /// Combines two streams together producing a stream of pairs in lockstep.
301
- /// Given two streams of length `n` and `m`, it produces a stream of length `min(n, m)`.
302
- def zip[A, B] { stream1: () => Any / emit[A] } { stream2: () => Any / emit[B] } { action: (A, B) => Any }: Unit = {
209
+ /// Terminates when either of them terminates.
210
+ def zip[A, B] { stream1: () => Unit / emit[A] } { stream2: () => Unit / emit[B] } { action: (A, B) => Unit }: Unit = {
303
211
  with source[A] { stream1 }
304
212
  with source[B] { stream2 }
305
213
 
@@ -423,7 +331,7 @@ def encodeUTF8[R] { stream: () => R / emit[Char] }: R / emit[Byte] =
423
331
  resume(encodeChar(char))
424
332
  }
425
333
 
426
- def feed(string: String) { reader: () => Unit / read[Char] } =
334
+ def feed[R](string: String) { reader: () => R / read[Char] } =
427
335
  feed(string.fromString) {
428
336
  decodeUTF8 {
429
337
  reader()
@@ -437,10 +345,129 @@ def each(string: String): Unit / emit[Char] =
437
345
  }
438
346
  }
439
347
 
348
+ def collectString { stream: () => Unit / emit[Char] }: String =
349
+ returning::collectString[Unit]{stream}.second
350
+
351
+ namespace returning {
352
+
353
+ /// Canonical handler of push streams that performs `action` for every
354
+ /// value emitted by `stream`.
355
+ def for[A, R] { stream: () => R / emit[A] } { action: A => Unit }: R =
356
+ try {
357
+ stream()
358
+ } with emit[A] { value =>
359
+ resume(action(value))
360
+ }
361
+
362
+ def boundary[R] { program: () => R / stop }: Option[R] =
363
+ try {
364
+ Some(program())
365
+ } with stop {
366
+ None()
367
+ }
368
+
369
+ def optionally[R] { program: () => R / stop }: Option[R] =
370
+ try {
371
+ Some(program())
372
+ } with stop {
373
+ None()
374
+ }
375
+
376
+ def index[A, R] { stream: () => R / emit[A] }: R / emit[Indexed[A]] = {
377
+ var i = 0;
378
+ try {
379
+ stream()
380
+ } with emit[A] { v =>
381
+ val c = i;
382
+ i = c + 1;
383
+ resume(do emit(Indexed(c, v)))
384
+ }
385
+ }
386
+
387
+ /// If `number` is zero or negative it does nothing
388
+ def limit[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop } = {
389
+ if (number <= 0) do stop();
390
+ var i = 1;
391
+ try {
392
+ stream()
393
+ } with emit[A] { v =>
394
+ if (i < number) {
395
+ i = i + 1;
396
+ resume(do emit(v))
397
+ } else {
398
+ do stop()
399
+ }
400
+ }
401
+ }
402
+
403
+ def sum[R] { stream : () => R / emit[Int] }: (R, Int) = {
404
+ var s = 0;
405
+ try {
406
+ (stream(), s)
407
+ } with emit[Int] { v =>
408
+ s = s + v;
409
+ resume(())
410
+ }
411
+ }
412
+
413
+ def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) =
414
+ try {
415
+ (stream(), Nil())
416
+ } with emit[A] { (v) =>
417
+ val (r, vs) = resume(());
418
+ (r, Cons(v, vs))
419
+ }
420
+
421
+ def collectArray[A, R] { stream: () => R / emit[A] }: (R, Array[A]) = {
422
+ var i = 0
423
+ var a = array::allocate(1)
424
+ try {
425
+ (stream(), a.resize(i))
426
+ } with emit[A] { (v) =>
427
+ if (i >= a.size) { a = a.resize(2 * a.size) }
428
+ a.unsafeSet(i, v)
429
+ i = i + 1
430
+ resume(())
431
+ }
432
+ }
433
+
434
+ def collectBytes[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
435
+ var i = 0
436
+ var a = bytearray::allocate(1)
437
+ try {
438
+ (stream(), a.resize(i))
439
+ } with emit[Byte] { (v) =>
440
+ if (i >= a.size) { a = a.resize(2 * a.size) }
441
+ a.unsafeSet(i, v)
442
+ i = i + 1
443
+ resume(())
444
+ }
445
+ }
446
+
440
447
  def collectString[R] { stream: () => R / emit[Char] }: (R, String) = {
441
448
  val (result, bytes) = collectBytes[R] { encodeUTF8 { stream } }
442
449
  (result, bytes.toString)
443
450
  }
444
451
 
445
- def collectString { stream: () => Any / emit[Char] }: String =
446
- collectString[Any]{stream}.second
452
+ def source[A, R] { stream: () => Unit / emit[A] } { reader: () => R / read[A] }: R = {
453
+ var next = box { None() }
454
+ next = box {
455
+ try {
456
+ stream()
457
+ next = box { None() }
458
+ None()
459
+ } with emit[A] { (v) =>
460
+ next = box { resume(()) }
461
+ Some(v)
462
+ }
463
+ }
464
+ try {
465
+ reader()
466
+ } with read[A] {
467
+ resume {
468
+ next().getOrElse { do stop() }
469
+ }
470
+ }
471
+ }
472
+
473
+ }
@@ -1,4 +1,4 @@
1
- import string/tty
1
+ import tty
2
2
  import process
3
3
  import bench
4
4
 
@@ -52,8 +52,8 @@ def assertEqual[A](obtained: A, expected: A, msg: String) { equals: (A, A) => Bo
52
52
  do assert(equals(obtained, expected), msg)
53
53
 
54
54
  def assertEqual[A](obtained: A, expected: A) { equals: (A, A) => Bool } { show: A => String }: Unit / { Assertion, Formatted } =
55
- do assert(equals(obtained, expected), Formatted::tryEmit(ANSI::RESET) ++ "Expected: ".dim ++ show(expected).green ++ "\n Obtained: ".dim ++ show(obtained).red)
56
- // NOTE: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55
+ do assert(equals(obtained, expected), Formatted::tryEmit(Escape::RESET) ++ "Expected: ".dim ++ show(expected).green ++ "\n Obtained: ".dim ++ show(obtained).red)
56
+ // NOTE: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
57
57
  // Here's an accidental capture! Can we prevent this somehow nicely?
58
58
 
59
59
 
@@ -0,0 +1,192 @@
1
+ module tty
2
+
3
+ /// Represents a TTY color.
4
+ /// - ANSI for the standard 16 terminal colors
5
+ /// - ANSI256 for standard 256 terminal colors
6
+ /// - NoColor for explicit "this doesn't have a set color"
7
+ type Color {
8
+ ANSI(code: Int)
9
+ ANSI256(code: Int)
10
+ NoColor()
11
+ }
12
+
13
+ /// Common terminal colors and their constructors
14
+ namespace Color {
15
+ // Standard ANSI colors
16
+ val BLACK = ANSI(0)
17
+ val RED = ANSI(1)
18
+ val GREEN = ANSI(2)
19
+ val YELLOW = ANSI(3)
20
+ val BLUE = ANSI(4)
21
+ val MAGENTA = ANSI(5)
22
+ val CYAN = ANSI(6)
23
+ val WHITE = ANSI(7)
24
+
25
+ // Bright ANSI colors
26
+ val BRIGHT_BLACK = ANSI(8)
27
+ val BRIGHT_RED = ANSI(9)
28
+ val BRIGHT_GREEN = ANSI(10)
29
+ val BRIGHT_YELLOW = ANSI(11)
30
+ val BRIGHT_BLUE = ANSI(12)
31
+ val BRIGHT_MAGENTA = ANSI(13)
32
+ val BRIGHT_CYAN = ANSI(14)
33
+ val BRIGHT_WHITE = ANSI(15)
34
+
35
+ /// Create an ANSI color from a code
36
+ def ansi(code: Int): Color =
37
+ if (code < 16) ANSI(code) else ANSI256(code)
38
+ }
39
+
40
+ /// Converts a color to its escape code
41
+ def toEscapeSeq(color: Color): String = color match {
42
+ case ANSI(code) =>
43
+ if (code < 8) (code + 30).show else (code + 82).show
44
+ case ANSI256(code) => "38;5;" ++ code.show
45
+ case NoColor() => ""
46
+ }
47
+
48
+ /// Common escapes
49
+ namespace Escape {
50
+ val CSI = "\u001b["
51
+ val OSC = "\u001b]"
52
+
53
+ val RESET = CSI ++ "0m"
54
+ val BOLD = CSI ++ "1m"
55
+ val FAINT = CSI ++ "2m"
56
+ val ITALIC = CSI ++ "3m"
57
+ val UNDERLINE = CSI ++ "4m"
58
+ val BLINK = CSI ++ "5m"
59
+ val REVERSE = CSI ++ "7m"
60
+ val CROSSOUT = CSI ++ "9m"
61
+ val OVERLINE = CSI ++ "53m"
62
+ }
63
+
64
+ def escape(code: String): String = Escape::CSI ++ code
65
+ def escapeOSC(code: String): String = Escape::OSC ++ code
66
+
67
+ // Cursor positioning
68
+ def cursorUp(x: Int): String = escape(x.show ++ "A")
69
+ def cursorDown(x: Int): String = escape(x.show ++ "B")
70
+ def cursorForward(x: Int): String = escape(x.show ++ "C")
71
+ def cursorBack(x: Int): String = escape(x.show ++ "D")
72
+ def cursorNextLine(x: Int): String = escape(x.show ++ "E")
73
+ def cursorPreviousLine(x: Int): String = escape(x.show ++ "F")
74
+ def cursorHorizontal(x: Int): String = escape(x.show ++ "G")
75
+ def cursorPosition(x: Int, y: Int): String = escape(y.show ++ ";" ++ x.show ++ "H")
76
+
77
+ // Screen manipulation
78
+ def eraseDisplay(x: Int): String = escape(x.show ++ "J")
79
+ def eraseLine(x: Int): String = escape(x.show ++ "K")
80
+ def scrollUp(x: Int): String = escape(x.show ++ "S")
81
+ def scrollDown(x: Int): String = escape(x.show ++ "T")
82
+ def saveCursorPosition(): String = escape("s")
83
+ def restoreCursorPosition(): String = escape("u")
84
+ def changeScrollingRegion(x: Int, y: Int): String = escape(x.show ++ ";" ++ y.show ++ "r")
85
+ def insertLine(x: Int): String = escape(x.show ++ "L")
86
+ def deleteLine(x: Int): String = escape(x.show ++ "M")
87
+
88
+ // Explicit values for eraseLine
89
+ def eraseLineRight(): String = escape("0K")
90
+ def eraseLineLeft(): String = escape("1K")
91
+ def eraseEntireLine(): String = escape("2K")
92
+
93
+ // Mouse
94
+ def enableMousePress(): String = escape("?9h")
95
+ def disableMousePress(): String = escape("?9l")
96
+ def enableMouse(): String = escape("?1000h")
97
+ def disableMouse(): String = escape("?1000l")
98
+ def enableMouseHighlight(): String = escape("?1001h")
99
+ def disableMouseHighlight(): String = escape("?1001l")
100
+ def enableMouseCellMotion(): String = escape("?1002h")
101
+ def disableMouseCellMotion(): String = escape("?1002l")
102
+ def enableMouseAllMotion(): String = escape("?1003h")
103
+ def disableMouseAllMotion(): String = escape("?1003l")
104
+ def enableMouseExtendedMode(): String = escape("?1006h")
105
+ def disableMouseExtendedMode(): String = escape("?1006l")
106
+ def enableMousePixelsMode(): String = escape("?1016h")
107
+ def disableMousePixelsMode(): String = escape("?1016l")
108
+
109
+ // Screen
110
+ def restoreScreen(): String = escape("?47l")
111
+ def saveScreen(): String = escape("?47h")
112
+ def altScreen(): String = escape("?1049h")
113
+ def exitAltScreen(): String = escape("?1049l")
114
+
115
+ // Bracketed paste
116
+ def enableBracketedPaste(): String = escape("?2004h")
117
+ def disableBracketedPaste(): String = escape("?2004l")
118
+ def startBracketedPaste(): String = escape("200~")
119
+ def endBracketedPaste(): String = escape("201~")
120
+
121
+ // Session
122
+ def setWindowTitle(s: String): String = escape("2;" ++ s)
123
+ def setForegroundColor(s: String): String = escape("10;" ++ s)
124
+ def setBackgroundColor(s: String): String = escape("11;" ++ s)
125
+ def setCursorColor(s: String): String = escape("12;" ++ s)
126
+ def showCursor(): String = escape("?25h")
127
+ def hideCursor(): String = escape("?25l")
128
+
129
+ def applyForegroundColor(color: Color): String =
130
+ escape(color.toEscapeSeq ++ "m")
131
+
132
+ def applyBackgroundColor(color: Color): String =
133
+ escape("48;" ++ color.toEscapeSeq ++ "m")
134
+
135
+ /// Inline images
136
+ /// See https://iterm2.com/documentation-images.html for protocol description
137
+ /// See [imgcat](https://iterm2.com/utilities/imgcat) for more usage details
138
+ def inlineImage(size: Int, base64Image: String) =
139
+ escape("1337;File=size=" ++ size.show ++ ";inline=1:" ++ base64Image ++ "\u0007")
140
+
141
+ /// Hyperlinks
142
+ /// https://iterm2.com/documentation-escape-codes.html
143
+ def hyperlink(text: String, url: String): String =
144
+ escapeOSC("8;;") ++ url ++ "\u0007" ++ text ++ escapeOSC("8;;") ++ "\u0007"
145
+
146
+ def attention(value: String) =
147
+ escapeOSC("1337;") ++ "RequestAttention=" ++ value ++ "\u0007"
148
+
149
+ namespace Screen {
150
+ def clear(): String = eraseDisplay(2) ++ cursorPosition(1, 1)
151
+ def clearLine(): String = eraseEntireLine()
152
+ }
153
+
154
+ def red(text: String) = Formatted::colored(text, Color::RED)
155
+ def green(text: String) = Formatted::colored(text, Color::GREEN)
156
+ def yellow(text: String) = Formatted::colored(text, Color::YELLOW)
157
+ def blue(text: String) = Formatted::colored(text, Color::BLUE)
158
+ def magenta(text: String) = Formatted::colored(text, Color::MAGENTA)
159
+ def cyan(text: String) = Formatted::colored(text, Color::CYAN)
160
+ def white(text: String) = Formatted::colored(text, Color::WHITE)
161
+
162
+ def dim(text: String) = Formatted::colored(text, Escape::FAINT)
163
+ def bold(text: String) = Formatted::colored(text, Escape::BOLD)
164
+ def underline(text: String) = Formatted::colored(text, Escape::UNDERLINE)
165
+ def italic(text: String) = Formatted::colored(text, Escape::ITALIC)
166
+
167
+ interface Formatted {
168
+ def supportsEscape(escape: String): Bool
169
+ }
170
+
171
+ namespace Formatted {
172
+ /// Run given block of code, allowing all formatting
173
+ def formatting[R] { prog : => R / Formatted }: R =
174
+ try { prog() } with Formatted {
175
+ def supportsEscape(escape: String) = resume(true)
176
+ }
177
+
178
+ /// Run given block of code, ignoring all formatting
179
+ def noFormatting[R] { prog : => R / Formatted }: R =
180
+ try { prog() } with Formatted {
181
+ def supportsEscape(escape: String) = resume(false)
182
+ }
183
+
184
+ def tryEmit(escape: String): String / Formatted =
185
+ if (do supportsEscape(escape)) escape else ""
186
+
187
+ def colored(text: String, escape: String): String / Formatted =
188
+ tryEmit(escape) ++ text ++ tryEmit(Escape::RESET)
189
+
190
+ def colored(text: String, color: Color): String / Formatted =
191
+ tryEmit(color.applyForegroundColor) ++ text ++ tryEmit(Escape::RESET)
192
+ }
@@ -1,4 +1,4 @@
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><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/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><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.110.0"><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=1733685326"><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 class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
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><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/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><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.110.0"><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=1734894944"><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 class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
2
2
  <i class="fa fa-search fa-lg" aria-role=none></i></button><div class="toolbar-search-bar-wrapper dropdown-menu dropdown-menu-right" aria-labelledby=toolbar-search><form action=https://www.eclipse.org/home/search method=get><div class=search-bar><input class=search-bar-input name=q placeholder=Search>
3
3
  <button>
4
4
  <i class="fa fa-search" type=submit></i></button></div></form></div></div><div class="toolbar-btn toolbar-user-menu-btn dropdown"><button class=dropdown-toggle id=toolbar-user-menu type=button data-toggle=dropdown tabindex=0 aria-label="User Menu">
@@ -47,15 +47,15 @@ open source software collaboration and innovation.</p></div><div class=mega-menu
47
47
  <i class="main-sidebar-item-icon fa fa-chevron-down" aria-hidden=true></i></a><div class=collapse id=legal-epl-20><ul class="main-sidebar-item-submenu list-unstyled"><li class=submenu-item><a class=link-unstyled href=/legal/epl-2.0/ target=_self>About</a></li><li class=submenu-item><a class=link-unstyled href=/org/documents/epl-2.0/EPL-2.0.html target=_self>Plain HTML</a></li><li class=submenu-item><a class=link-unstyled href=/org/documents/epl-2.0/EPL-2.0.txt target=_self>Plain Text</a></li><li class=submenu-item><a class=link-unstyled href=/org/documents/epl-2.0/EPL-2.0.pdf target=_self>PDF</a></li><li class=submenu-item><a class=link-unstyled href=/legal/epl-2.0/faq/ target=_self>FAQ</a></li></ul></div></li></li><li class="main-sidebar-item main-sidebar-item-indented"><li class="main-sidebar-item main-sidebar-item-indented"><a class=link-unstyled role=button data-toggle=collapse href=#legal-epl-10 aria-expanded=false aria-controls=legal-epl-10><span>EPL-1.0</span>
48
48
  <i class="main-sidebar-item-icon fa fa-chevron-down" aria-hidden=true></i></a><div class=collapse id=legal-epl-10><ul class="main-sidebar-item-submenu list-unstyled"><li class=submenu-item><a class=link-unstyled href=/org/documents/epl-v10.php target=_self>About</a></li><li class=submenu-item><a class=link-unstyled href=/org/documents/epl-v10.html target=_self>Plain HTML</a></li><li class=submenu-item><a class=link-unstyled href=/org/documents/epl-1.0/EPL-1.0.txt target=_self>Plain Text</a></li><li class=submenu-item><a class=link-unstyled href=/legal/epl/faq target=_self>FAQ</a></li></ul></div></li></li><li class="main-sidebar-item main-sidebar-item-indented"><li class="main-sidebar-item main-sidebar-item-indented"><a class=link-unstyled role=button data-toggle=collapse href=#legal-licenses aria-expanded=false aria-controls=legal-licenses><span>Licenses</span>
49
49
  <i class="main-sidebar-item-icon fa fa-chevron-down" aria-hidden=true></i></a><div class=collapse id=legal-licenses><ul class="main-sidebar-item-submenu list-unstyled"><li class=submenu-item><a class=link-unstyled href=/legal/licenses#approved target=_self>Approved 3rd Party</a></li><li class=submenu-item><a class=link-unstyled href=/legal/licenses#nonapproved target=_self>Non Approved</a></li><li class=submenu-item><a class=link-unstyled href=/projects/handbook/#ip-copyright-headers target=_self>File Headers</a></li><li class=submenu-item><a class=link-unstyled href=/legal/non-code-licenses target=_self>Docs & Examples</a></li></ul></div></li></li><li class="main-sidebar-item main-sidebar-item-indented"><li class="main-sidebar-item main-sidebar-item-indented"><a class=link-unstyled role=button data-toggle=collapse href=#legal-specs aria-expanded=false aria-controls=legal-specs><span>Specifications</span>
50
- <i class="main-sidebar-item-icon fa fa-chevron-down" aria-hidden=true></i></a><div class=collapse id=legal-specs><ul class="main-sidebar-item-submenu list-unstyled"><li class=submenu-item><a class=link-unstyled href=/projects/efsp/ target=_self>Specifications Process</a></li><li class=submenu-item><a class=link-unstyled href=/projects/efsp/operations.php target=_self>Specifications Operations</a></li><li class=submenu-item><a class=link-unstyled href=/legal/efsl target=_self>Specification License</a></li><li class=submenu-item><a class=link-unstyled href=/legal/tck target=_self>TCK License</a></li></ul></div></li></li></ul></aside></div></div></div></main><div class="eclipsefdn-featured-footer featured-footer" id=featured-footer data-publish-target=eclipse_org><div class=container><div class=row><div class="col-sm-24 featured-container"></div></div></div></div><p id=back-to-top><a class=visible-xs href=#>Back to the top</a></p><footer class=footer id=footer><div class=container><div class="footer-end-social-container margin-bottom-30"><div class=footer-end-social><p class="footer-end-social-text hidden-xs">Follow Us:</p><ul class="footer-end-social-links list-inline"><li><a class=link-unstyled href=https://twitter.com/EclipseFdn title="Twitter account"><span class="fa fa-stack"><i class="fa fa-circle fa-stack-2x" aria-hidden=true></i>
51
- <i class="fa fa-twitter fa-stack-1x fa-inverse" aria-hidden=true></i>
52
- <span class=sr-only>Twitter account</span></span></a></li><li><a class=link-unstyled href=https://www.facebook.com/eclipse.org title="Facebook account"><span class="fa fa-stack"><i class="fa fa-circle fa-stack-2x" aria-hidden=true></i>
53
- <i class="fa fa-facebook fa-stack-1x fa-inverse" aria-hidden=true></i>
54
- <span class=sr-only>Facebook account</span></span></a></li><li><a class=link-unstyled href=https://www.youtube.com/user/EclipseFdn title="Youtube account"><span class="fa fa-stack"><i class="fa fa-circle fa-stack-2x" aria-hidden=true></i>
55
- <i class="fa fa-youtube-play fa-stack-1x fa-inverse" aria-hidden=true></i>
56
- <span class=sr-only>Youtube account</span></span></a></li><li><a class=link-unstyled href=https://www.linkedin.com/company/eclipse-foundation title="Linkedin account"><span class="fa fa-stack"><i class="fa fa-circle fa-stack-2x" aria-hidden=true></i>
57
- <i class="fa fa-linkedin fa-stack-1x fa-inverse" aria-hidden=true></i>
50
+ <i class="main-sidebar-item-icon fa fa-chevron-down" aria-hidden=true></i></a><div class=collapse id=legal-specs><ul class="main-sidebar-item-submenu list-unstyled"><li class=submenu-item><a class=link-unstyled href=/projects/efsp/ target=_self>Specifications Process</a></li><li class=submenu-item><a class=link-unstyled href=/projects/efsp/operations.php target=_self>Specifications Operations</a></li><li class=submenu-item><a class=link-unstyled href=/legal/efsl target=_self>Specification License</a></li><li class=submenu-item><a class=link-unstyled href=/legal/tck target=_self>TCK License</a></li></ul></div></li></li></ul></aside></div></div></div></main><div class="eclipsefdn-featured-footer featured-footer" id=featured-footer data-publish-target=eclipse_org><div class=container><div class=row><div class="col-sm-24 featured-container"></div></div></div></div><p id=back-to-top><a class=visible-xs href=#>Back to the top</a></p><footer class=footer id=footer><div class=container><div class="footer-end-social-container margin-bottom-30"><div class=footer-end-social><p class="footer-end-social-text hidden-xs">Follow Us:</p><ul class="footer-end-social-links list-inline"><li><a class=link-unstyled href=https://twitter.com/EclipseFdn title="Twitter account"><span class=fa-stack><i class="fa-solid fa-circle fa-stack-2x" aria-hidden=true></i>
51
+ <i class="fa-brands fa-x-twitter fa-stack-1x fa-inverse" aria-hidden=true></i>
52
+ <span class=sr-only>Twitter account</span></span></a></li><li><a class=link-unstyled href=https://www.facebook.com/eclipse.org title="Facebook account"><span class=fa-stack><i class="fa-solid fa-circle fa-stack-2x" aria-hidden=true></i>
53
+ <i class="fa-brands fa-facebook-f fa-stack-1x fa-inverse" aria-hidden=true></i>
54
+ <span class=sr-only>Facebook account</span></span></a></li><li><a class=link-unstyled href=https://www.youtube.com/user/EclipseFdn title="Youtube account"><span class=fa-stack><i class="fa-solid fa-circle fa-stack-2x" aria-hidden=true></i>
55
+ <i class="fa-brands fa-youtube fa-stack-1x fa-inverse" aria-hidden=true></i>
56
+ <span class=sr-only>Youtube account</span></span></a></li><li><a class=link-unstyled href=https://www.linkedin.com/company/eclipse-foundation title="Linkedin account"><span class=fa-stack><i class="fa-solid fa-circle fa-stack-2x" aria-hidden=true></i>
57
+ <i class="fa-brands fa-linkedin-in fa-stack-1x fa-inverse" aria-hidden=true></i>
58
58
  <span class=sr-only>Linkedin account</span></span></a></li></ul></div></div><div class="footer-sections row equal-height-md font-bold"><div class=col-md-15><div class=row><section id=footer-eclipse-foundation class="footer-section col-sm-8"><div class=menu-heading>Eclipse Foundation</div><ul class=nav><li><a href=https://www.eclipse.org/org/>About</a></li><li><a href=https://projects.eclipse.org/>Projects</a></li><li><a href=https://www.eclipse.org/collaborations/>Collaborations</a></li><li><a href=https://www.eclipse.org/membership/>Membership</a></li><li><a href=https://www.eclipse.org/sponsor/>Sponsor</a></li></ul></section><section id=footer-legal class="footer-section col-sm-8"><div class=menu-heading>Legal</div><ul class=nav><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/org/documents/Community_Code_of_Conduct.php>Code of Conduct</a></li><li><a href=https://www.eclipse.org/legal/>Legal Resources</a></li><li><a class=toolbar-manage-cookies href=# onclick=event.preventDefault()>Manage Cookies</a></li></ul></section><section id=footer-more class="footer-section col-sm-8"><div class=menu-heading>More</div><ul class=nav><li><a href=https://www.eclipse.org/security/>Report a Vulnerability</a></li><li><a href=https://status.eclipse.org/>Service Status</a></li><li><a href=https://www.eclipse.org/org/foundation/contact.php>Contact Us</a></li><li><a href=https://www.eclipse.org/projects/support/>Support</a></li></ul></section></div></div><div id=footer-end class="footer-section col-md-8 col-md-offset-1 col-sm-24"><div class=footer-end-newsletter><form id=mc-embedded-subscribe-form action=https://eclipsecon.us6.list-manage.com/subscribe/post method=post novalidate target=_blank><label class=footer-end-newsletter-label for=email>Subscribe to our Newsletter</label><div class=footer-end-newsletter-input-wrapper><input class=footer-end-newsletter-input type=email id=email name=EMAIL autocomplete=email placeholder="Enter your email address"><div><i class="fa fa-solid fa-envelope fa-lg" aria-hidden=true></i></div></div><input type=hidden name=u value=eaf9e1f06f194eadc66788a85>
59
59
  <input type=hidden name=id value=46e57eacf1>
60
- <input id=mc-embedded-subscribe type=submit name=subscribe hidden></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1733685326"></script>
60
+ <input id=mc-embedded-subscribe type=submit name=subscribe hidden></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1734894944"></script>
61
61
  <script>(function(){})(jQuery,document)</script></div></body></html>