Skip to content

Commit 36cd344

Browse files
authored
Merge branch 'dev' into eq_gen_language_server
2 parents 5523a58 + a4e3aa2 commit 36cd344

File tree

111 files changed

+1658
-613
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+1658
-613
lines changed

Diff for: .github/workflows/bundle.yaml

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
on:
2+
workflow_dispatch: # so we can run the workflow manually as well
3+
push:
4+
tags:
5+
- 'v*'
6+
7+
permissions:
8+
contents: write
9+
10+
env:
11+
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
12+
13+
name: bundle
14+
jobs:
15+
build:
16+
name: Bundle Koka
17+
runs-on: ${{ matrix.os }}
18+
strategy:
19+
matrix:
20+
# macOS 13 is x64, later versions are arm64
21+
# we build on the oldest ubuntu version for better binary compatibility.
22+
os: [windows-latest, macOS-latest, macOS-13, ubuntu-20.04, ubuntu-22.04-arm]
23+
24+
steps:
25+
# Checkout
26+
- name: Checkout repository
27+
uses: actions/checkout@v4
28+
with:
29+
submodules: true
30+
31+
# Cache setup for vcpkg (https://learn.microsoft.com/en-us/vcpkg/consume/binary-caching-github-actions-cache)
32+
- name: Setup vcpkg cache
33+
uses: actions/github-script@v7
34+
with:
35+
script: |
36+
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
37+
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
38+
39+
# Use a VS shell on Windows (so `cl` is on the PATH): https://github.com/egor-tensin/vs-shell (MIT license)
40+
- name: Set up Visual Studio shell
41+
uses: egor-tensin/vs-shell@v2
42+
if: runner.os == 'Windows' && runner.arch == 'X64'
43+
with:
44+
arch: x64
45+
46+
# Set up stack and cache dependencies: https://github.com/freckle/stack-action (MIT license)
47+
- name: Build compiler
48+
uses: freckle/stack-action@v5
49+
with:
50+
test: false
51+
stack-build-arguments: ""
52+
cache-save-always: true
53+
54+
# Bundle
55+
- name: Build libraries
56+
if: runner.os == 'Windows'
57+
run: |
58+
$env:VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT
59+
stack exec koka -- -e -O2 util/bundle
60+
61+
- name: Build libraries
62+
if: runner.os != 'Windows'
63+
run: |
64+
stack exec koka -- -e -O2 util/bundle
65+
66+
# VS code extension
67+
- name: Package VS code extension
68+
if: runner.os == 'Windows' && runner.arch == 'X64'
69+
working-directory: support/vscode/koka.language-koka
70+
run: |
71+
npm install
72+
npm run build
73+
74+
# Create a release: https://github.com/softprops/action-gh-release (MIT license)
75+
- name: Release
76+
uses: softprops/action-gh-release@v2
77+
if: startsWith(github.ref, 'refs/tags/') # only release if tagged with a version
78+
with:
79+
files: |
80+
bundle/**/*.tar.gz
81+
support/vscode/koka.language-koka/*.vsix
82+
util/install.bat
83+
util/install.sh
84+
draft: true
85+
body_path: util/release.md
86+

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
.vs/
66
.vscode/
77
support/vscode/koka.language-koka/whatsnew.md
8+
support/vscode/koka.language-koka/dist
89
src/Syntax/Lexer.hs.gen
910
node_modules/
1011
out/

Diff for: kklib/include/kklib/platform.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,12 @@
147147
#define WIN32 1
148148
#endif
149149

150-
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
150+
#if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) // must come first as we consider ARM64EC as ARM64
151+
#define KK_ARCH_ARM64 1
152+
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
151153
#define KK_ARCH_X64 1
152154
#elif defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_X86_) || defined(__X86__)
153155
#define KK_ARCH_X86 1
154-
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC)
155-
#define KK_ARCH_ARM64 1
156156
#elif defined(__arm__) || defined(_ARM) || defined(_M_ARM) || defined(_M_ARMT) || defined(__arm)
157157
#define KK_ARCH_ARM32 1
158158
#elif defined(__riscv) || defined(_M_RISCV)

Diff for: kklib/src/bytes.c

+8
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,16 @@ kk_ssize_t kk_decl_pure kk_bytes_count_pattern_borrow(kk_bytes_t b, kk_bytes_t p
152152
kk_bytes_t kk_bytes_cat(kk_bytes_t b1, kk_bytes_t b2, kk_context_t* ctx) {
153153
kk_ssize_t len1;
154154
const uint8_t* s1 = kk_bytes_buf_borrow(b1, &len1, ctx);
155+
if(len1 == 0) {
156+
kk_bytes_drop(b1, ctx);
157+
return b2;
158+
}
155159
kk_ssize_t len2;
156160
const uint8_t* s2 = kk_bytes_buf_borrow(b2, &len2, ctx);
161+
if(len2 == 0) {
162+
kk_bytes_drop(b2, ctx);
163+
return b1;
164+
}
157165
uint8_t* p;
158166
kk_bytes_t t = kk_bytes_alloc_buf(len1 + len2, &p, ctx );
159167
kk_memcpy(p, s1, len1);

Diff for: kklib/src/os.c

+28-7
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,36 @@ kk_decl_export int kk_os_write_text_file(kk_string_t path, kk_string_t content,
246246

247247
kk_decl_export int kk_os_read_line(kk_string_t* result, kk_context_t* ctx)
248248
{
249+
kk_string_t line = kk_string_empty();
249250
char buf[1024];
250-
if (fgets(buf, 1023, stdin) == NULL) return errno;
251-
buf[1023] = 0; // ensure zero termination
252-
const size_t len = strlen(buf);
253-
if (len > 0 && buf[len-1] == '\n') {
254-
buf[len-1] = 0; // remove possible ending newline character
251+
bool newline_found = false;
252+
253+
// read until '\n', EOF, or error
254+
while (!newline_found && fgets(buf, sizeof buf, stdin) != NULL) {
255+
kk_ssize_t len = kk_sstrlen(buf); // assumes no embedded '\0' characters
256+
257+
// check if we have a reached a newline character
258+
if (len > 0 && buf[len-1] == '\n') {
259+
newline_found = true;
260+
buf[--len] = '\0'; // remove newline
261+
}
262+
263+
// append buf to line
264+
kk_string_t buf_str = kk_string_alloc_from_qutf8n(len, buf, ctx);
265+
line = kk_string_cat(line, buf_str, ctx);
266+
}
267+
268+
// success if we reach '\n', or EOF with a non-empty line
269+
// this mimics the behaviour of `fgets`
270+
if(newline_found || (feof(stdin) && !kk_string_is_empty_borrow(line, ctx))) {
271+
*result = line;
272+
return 0;
273+
}
274+
else {
275+
// error or EOF with an empty line
276+
kk_string_drop(line, ctx);
277+
return ferror(stdin) ? errno : EOF;
255278
}
256-
*result = kk_string_alloc_from_qutf8(buf, ctx);
257-
return 0;
258279
}
259280

260281

Diff for: lib/std/core/delayed.kk

+25-10
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,43 @@ import std/core/unsafe
1717
// Delayed values
1818
// ----------------------------------------------------------------------------
1919

20+
reference type computation<e, a>
21+
con XComputation( action : () -> e a )
22+
con XDone( value : a )
23+
con XBlocking
24+
2025
// Delayed (or _lazy_) values are computed (with effect `:e`) only the first time
2126
// `force` is called and cached afterwards.
2227
abstract value type delayed<e,a>
23-
con XDelay( dref : ref<global,either<() -> e a,a>> )
28+
con XDelay( dref : ref<global,computation<e,a>> )
2429

2530
// Create a new `:delayed` value.
2631
pub fun delay( action : () -> e a ) : delayed<e,a>
2732
unsafe-total
28-
val r : ref<global,either<_,_>> = ref(Left(action))
33+
val r : ref<global,computation<_,_>> = ref(XComputation(action))
2934
XDelay(r)
3035

36+
// Create a new `:delayed` value.
37+
pub fun memo( value : a ) : delayed<e, a>
38+
unsafe-total
39+
val r : ref<global,computation<_,_>> = ref(XDone(value))
40+
XDelay(r)
41+
42+
pub fun force/go( delayed : delayed<e,a> ) : <div,read<global>,write<global>,alloc<global>|e> a
43+
val r = delayed.dref
44+
match !r
45+
XDone(x) -> x
46+
XBlocking -> delayed.go()
47+
XComputation(action) ->
48+
r := XBlocking // ensure that action can be unique
49+
val x = mask-st{ mask<div>(action) }()
50+
r := XDone(x)
51+
x
52+
3153
// Force a delayed value; the value is computed only on the first
3254
// call to `force` and cached afterwards.
3355
pub fun force( delayed : delayed<e,a> ) : e a
34-
unsafe-total
35-
val r = delayed.dref
36-
match !r
37-
Right(x) -> x
38-
Left(action) ->
39-
val x = mask-st{ mask<div>(action) }()
40-
r := Right(x)
41-
x
56+
unsafe-total(fn() -> force/go(delayed))
4257

4358
// Given a total function to calculate a value `:a`, return
4459
// a total function that only calculates the value once and then

Diff for: lib/std/core/hnd.kk

+1-1
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ fun prompt-local-var(loc:local-var<s,a>, res : b ) : <div,local<s>|e> b
463463
val v = loc
464464
yield-cont(fn(cont,x){ loc := v; prompt-local-var(std/core/types/@byref(loc),cont(x)) } ) // restore state early before the resume
465465

466-
pub inline fun local-var(init:a, action: (l:local-var<s,a>) -> <local<s>|e> b ) : <local<s>|e> b
466+
pub inline fun local-var(init:a, action: (@local-var:local-var<s,a>) -> <local<s>|e> b ) : <local<s>|e> b
467467
pretend-no-div
468468
val loc : local-var<_,_> = local-new(init)
469469
val res = cast-ev1(action)(std/core/types/@byref(loc))

Diff for: lib/std/core/list.kk

+19-22
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,19 @@ import std/core/vector
2020

2121

2222
// Return the head of list if the list is not empty.
23-
pub fun head( xs : list<a> ) : maybe<a>
23+
pub fbip fun head( xs : list<a> ) : maybe<a>
2424
match xs
2525
Cons(x) -> Just(x)
2626
_ -> Nothing
2727

2828
// Return the head of list with a default value in case the list is empty.
29-
pub fun default/head( xs : list<a>, default : a ) : a
29+
pub fbip fun default/head( xs : list<a>, default : a ) : a
3030
match xs
3131
Cons(x) -> x
3232
_ -> default
3333

3434
// Return the tail of list. Returns the empty list if `xs` is empty.
35-
pub fun tail( xs : list<a> ) : list<a>
35+
pub fbip fun tail( xs : list<a> ) : list<a>
3636
match xs
3737
Cons(_,xx) -> xx
3838
_ -> []
@@ -49,7 +49,7 @@ pub fip fun is-empty( ^xs : list<a> ) : bool
4949
// ----------------------------------------------------------------------------
5050

5151
// Returns a singleton list.
52-
pub fun single(x)
52+
pub fip(1) fun single(x)
5353
[x]
5454

5555
// Returns the length of a list.
@@ -130,7 +130,7 @@ pub fun show-list( xs : list<a>, show-elem : (a) -> e string ) : e string
130130

131131
// Zip two lists together by pairing the corresponding elements.
132132
// The returned list is only as long as the smallest input list.
133-
pub fun zip( xs : list<a>, ys : list<b> ) : list<(a,b)>
133+
pub fbip fun zip( xs : list<a>, ys : list<b> ) : list<(a,b)>
134134
match xs
135135
Cons(x,xx) -> match ys
136136
Cons(y,yy) -> Cons((x,y),zip(xx,yy))
@@ -139,7 +139,7 @@ pub fun zip( xs : list<a>, ys : list<b> ) : list<(a,b)>
139139

140140
// Zip two lists together by apply a function `f` to all corresponding elements.
141141
// The returned list is only as long as the smallest input list.
142-
pub fun zipwith( xs : list<a>, ys :list<b>, f : (a,b) -> e c ) : e list<c>
142+
pub fbip fun zipwith( xs : list<a>, ys :list<b>, ^f : (a,b) -> e c ) : e list<c>
143143
match xs
144144
Cons(x,xx) -> match ys
145145
Cons(y,yy) -> Cons(f(x,y),zipwith(xx,yy,f))
@@ -149,18 +149,18 @@ pub fun zipwith( xs : list<a>, ys :list<b>, f : (a,b) -> e c ) : e list<c>
149149
// Zip two lists together by apply a function `f` to all corresponding elements
150150
// and their index in the list.
151151
// The returned list is only as long as the smallest input list.
152-
pub fun zipwith-indexed( xs0 : list<a>, ys0 :list<b>, f : (int,a,b) -> e c ) : e list<c>
153-
fun zipwith-iter( i, xs, ys )
154-
match xs
155-
Cons(x,xx) -> match ys
156-
Cons(y,yy) -> Cons(f(i,x,y),zipwith-iter(i+1,xx,yy))
157-
Nil -> Nil
152+
pub fbip fun zipwith-indexed( xs0 : list<a>, ys0 :list<b>, ^f : (int,a,b) -> e c ) : e list<c>
153+
zipwith-iter(0,xs0,ys0,f)
154+
155+
fbip fun zipwith-iter( i, xs, ys, ^f )
156+
match xs
157+
Cons(x,xx) -> match ys
158+
Cons(y,yy) -> Cons(f(i,x,y),zipwith-iter(i+1,xx,yy,f))
158159
Nil -> Nil
159-
zipwith-iter(0,xs0,ys0)
160+
Nil -> Nil
160161

161162
// Unzip a list of pairs into two lists
162163
pub fun unzip( xs : list<(a,b)> ) : (list<a>,list<b>)
163-
// todo: implement TRMC for multiple results
164164
fun iter( ys, acc1, acc2 )
165165
match ys
166166
Cons((x,y),xx) -> iter(xx,acc1 ++ ctx Cons(x,_),acc2 ++ ctx Cons(y,_))
@@ -169,7 +169,6 @@ pub fun unzip( xs : list<(a,b)> ) : (list<a>,list<b>)
169169

170170
// Unzip a list of triples into three lists
171171
pub fun unzip3( xs : list<(a,b,c)>) : (list<a>,list<b>,list<c>)
172-
// todo: implement TRMC for multiple results
173172
fun iter( ys, acc1, acc2, acc3 )
174173
match ys
175174
Cons((x,y,z),xx) -> iter(xx,acc1 ++ ctx Cons(x,_),acc2 ++ ctx Cons(y,_),acc3 ++ ctx Cons(z,_))
@@ -178,7 +177,6 @@ pub fun unzip3( xs : list<(a,b,c)>) : (list<a>,list<b>,list<c>)
178177

179178
// Unzip a list of quadruples into four lists
180179
pub fun unzip4( xs : list<(a,b,c,d)>) : (list<a>,list<b>,list<c>,list<d>)
181-
// todo: implement TRMC for multiple results
182180
fun iter( ys, acc1, acc2, acc3, acc4 )
183181
match ys
184182
Cons((x,y,z,w),xx) -> iter(xx,acc1 ++ ctx Cons(x,_),acc2 ++ ctx Cons(y,_),acc3 ++ ctx Cons(z,_),acc4 ++ ctx Cons(w,_))
@@ -198,7 +196,7 @@ pub fun drop( xs : list<a>, n : int ) : list<a>
198196
_ -> xs
199197

200198
// Apply a function `f` to each element of the input list in sequence.
201-
pub fun map(xs : list<a>, f : a -> e b) : e list<b>
199+
pub fip fun map(xs : list<a>, ^f : a -> e b) : e list<b>
202200
match xs
203201
Cons(x,xx) -> Cons(f(x), xx.map(f))
204202
Nil -> Nil
@@ -285,12 +283,11 @@ pub fun split( xs : list<a>, n : int ) : (list<a>, list<a>)
285283
(xs.take(n), xs.drop(n))
286284

287285
pub fun span( xs : list<a>, predicate : a -> e bool ) : e (list<a>,list<a>)
288-
// todo: implement TRMC with multiple results to avoid the reverse
289-
fun span-acc( ys, acc)
286+
fun span-acc( ys, acc )
290287
match ys
291-
Cons(y,yy) -> if y.predicate then yy.span-acc(Cons(y,acc)) else (acc.reverse,ys)
292-
_ -> (acc.reverse, ys)
293-
xs.span-acc( [] )
288+
Cons(y,yy) -> if y.predicate then yy.span-acc(acc ++ ctx Cons(y, _)) else (acc ++. [],ys)
289+
_ -> (acc ++. [], ys)
290+
xs.span-acc( ctx _ )
294291

295292
// Keep only those initial elements that satisfy `predicate`
296293
pub fun take-while( xs : list<a>, predicate : a -> e bool ) : e list<a>

Diff for: lib/std/core/maybe.kk

+8-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@ pub fun default( m : maybe<a>, nothing : a ) : a
2626
Just(x) -> x
2727

2828
// Get the value of the `Just` constructor or raise an exception
29-
pub fun unjust( m : maybe<a> ) : exn a
29+
pub fun unjust( m : maybe<a>, ?kk-file-line: string) : exn a
3030
match m
3131
Just(x) -> x
32-
Nothing -> throw("unexpected Nothing in std/core/maybe/unjust")
32+
Nothing -> throw("unexpected Nothing in " ++ ?kk-file-line)
33+
34+
// Get the value of the `Just` constructor or raise an exception with `error-msg`
35+
pub fun expect( m : maybe<a>, error-msg: string) : exn a
36+
match m
37+
Just(x) -> x
38+
Nothing -> throw(error-msg)
3339

3440
pub fun map( m : maybe<a>, f : a -> e b ) : e maybe<b>
3541
match m

Diff for: lib/std/core/maybe2.kk

+8-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@ pub fun default( m : maybe2<a,b>, nothing : (a,b) ) : (a,b)
2626
Just2(x,y) -> (x,y)
2727

2828
// Get the value of the `Just` constructor or raise an exception
29-
pub fun unjust2( m : maybe2<a,b> ) : exn (a,b)
29+
pub fun unjust( m : maybe2<a,b>, ?kk-file-line: string) : exn (a,b)
3030
match m
3131
Just2(x,y) -> (x,y)
32-
Nothing2 -> throw("unexpected Nothing2 in std/core/maybe/unjust2")
32+
Nothing2 -> throw("unexpected Nothing2 in " ++ ?kk-file-line)
33+
34+
// Get the value of the `Just` constructor or raise an exception
35+
pub fun expect( m : maybe2<a,b>, error-msg: string) : exn (a,b)
36+
match m
37+
Just2(x,y) -> (x,y)
38+
Nothing2 -> throw(error-msg)
3339

3440
pub fun map( m : maybe2<a,b>, f : (a,b) -> e (c,d) ) : e maybe2<c,d>
3541
match m

0 commit comments

Comments
 (0)