From 62e42328e1523ee6be222d6c1dbdea9c2a836758 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Thu, 6 Nov 2025 21:26:37 -0800 Subject: [PATCH 1/4] fix test issues --- src/compiler/tests/pipe.test.ts | 4 ++-- src/compiler/tests/ribbit.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/tests/pipe.test.ts b/src/compiler/tests/pipe.test.ts index 1d08dec..06d56c3 100644 --- a/src/compiler/tests/pipe.test.ts +++ b/src/compiler/tests/pipe.test.ts @@ -89,7 +89,7 @@ describe('pipe expressions', () => { test('pipe with prelude function (echo)', () => { expect(` get-msg = do: 'hello' end - get-msg | echo - `).toEvaluateTo(null) + get-msg | length + `).toEvaluateTo(5) }) }) diff --git a/src/compiler/tests/ribbit.test.ts b/src/compiler/tests/ribbit.test.ts index e2bb6c2..def34c4 100644 --- a/src/compiler/tests/ribbit.test.ts +++ b/src/compiler/tests/ribbit.test.ts @@ -83,7 +83,7 @@ end test('custom tags', () => { expect(` -list = tag ul class=list +list = tag ul class='list' ribbit: list: li border-bottom='1px solid black' one From 3ac606d0b237801d672a7ddb773e0028d2d3a784 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Thu, 6 Nov 2025 21:38:04 -0800 Subject: [PATCH 2/4] prelude is now preloaded --- src/prelude/tests/prelude.test.ts | 334 +++++++++++++++--------------- 1 file changed, 167 insertions(+), 167 deletions(-) diff --git a/src/prelude/tests/prelude.test.ts b/src/prelude/tests/prelude.test.ts index 3125f9b..2794255 100644 --- a/src/prelude/tests/prelude.test.ts +++ b/src/prelude/tests/prelude.test.ts @@ -3,185 +3,185 @@ import { globals } from '#prelude' describe('string operations', () => { test('to-upper converts to uppercase', async () => { - await expect(`str.to-upper 'hello'`).toEvaluateTo('HELLO', globals) - await expect(`str.to-upper 'Hello World!'`).toEvaluateTo('HELLO WORLD!', globals) + await expect(`str.to-upper 'hello'`).toEvaluateTo('HELLO') + await expect(`str.to-upper 'Hello World!'`).toEvaluateTo('HELLO WORLD!') }) test('to-lower converts to lowercase', async () => { - await expect(`str.to-lower 'HELLO'`).toEvaluateTo('hello', globals) - await expect(`str.to-lower 'Hello World!'`).toEvaluateTo('hello world!', globals) + await expect(`str.to-lower 'HELLO'`).toEvaluateTo('hello') + await expect(`str.to-lower 'Hello World!'`).toEvaluateTo('hello world!') }) test('trim removes whitespace', async () => { - await expect(`str.trim ' hello '`).toEvaluateTo('hello', globals) - await expect(`str.trim '\\n\\thello\\t\\n'`).toEvaluateTo('hello', globals) + await expect(`str.trim ' hello '`).toEvaluateTo('hello') + await expect(`str.trim '\\n\\thello\\t\\n'`).toEvaluateTo('hello') }) test('split divides string by separator', async () => { - await expect(`str.split 'a,b,c' ','`).toEvaluateTo(['a', 'b', 'c'], globals) - await expect(`str.split 'hello' ''`).toEvaluateTo(['h', 'e', 'l', 'l', 'o'], globals) + await expect(`str.split 'a,b,c' ','`).toEvaluateTo(['a', 'b', 'c']) + await expect(`str.split 'hello' ''`).toEvaluateTo(['h', 'e', 'l', 'l', 'o']) }) test('split with comma separator', async () => { - await expect(`str.split 'a,b,c' ','`).toEvaluateTo(['a', 'b', 'c'], globals) + await expect(`str.split 'a,b,c' ','`).toEvaluateTo(['a', 'b', 'c']) }) test('join combines array elements', async () => { - await expect(`str.join ['a' 'b' 'c'] '-'`).toEvaluateTo('a-b-c', globals) - await expect(`str.join ['hello' 'world'] ' '`).toEvaluateTo('hello world', globals) + await expect(`str.join ['a' 'b' 'c'] '-'`).toEvaluateTo('a-b-c') + await expect(`str.join ['hello' 'world'] ' '`).toEvaluateTo('hello world') }) test('join with comma separator', async () => { - await expect(`str.join ['a' 'b' 'c'] ','`).toEvaluateTo('a,b,c', globals) + await expect(`str.join ['a' 'b' 'c'] ','`).toEvaluateTo('a,b,c') }) test('starts-with? checks string prefix', async () => { - await expect(`str.starts-with? 'hello' 'hel'`).toEvaluateTo(true, globals) - await expect(`str.starts-with? 'hello' 'bye'`).toEvaluateTo(false, globals) + await expect(`str.starts-with? 'hello' 'hel'`).toEvaluateTo(true) + await expect(`str.starts-with? 'hello' 'bye'`).toEvaluateTo(false) }) test('ends-with? checks string suffix', async () => { - await expect(`str.ends-with? 'hello' 'lo'`).toEvaluateTo(true, globals) - await expect(`str.ends-with? 'hello' 'he'`).toEvaluateTo(false, globals) + await expect(`str.ends-with? 'hello' 'lo'`).toEvaluateTo(true) + await expect(`str.ends-with? 'hello' 'he'`).toEvaluateTo(false) }) test('contains? checks for substring', async () => { - await expect(`str.contains? 'hello world' 'o w'`).toEvaluateTo(true, globals) - await expect(`str.contains? 'hello' 'bye'`).toEvaluateTo(false, globals) + await expect(`str.contains? 'hello world' 'o w'`).toEvaluateTo(true) + await expect(`str.contains? 'hello' 'bye'`).toEvaluateTo(false) }) test('empty? checks if string is empty', async () => { - await expect(`str.empty? ''`).toEvaluateTo(true, globals) - await expect(`str.empty? 'hello'`).toEvaluateTo(false, globals) + await expect(`str.empty? ''`).toEvaluateTo(true) + await expect(`str.empty? 'hello'`).toEvaluateTo(false) }) test('replace replaces first occurrence', async () => { - await expect(`str.replace 'hello hello' 'hello' 'hi'`).toEvaluateTo('hi hello', globals) + await expect(`str.replace 'hello hello' 'hello' 'hi'`).toEvaluateTo('hi hello') }) test('replace-all replaces all occurrences', async () => { - await expect(`str.replace-all 'hello hello' 'hello' 'hi'`).toEvaluateTo('hi hi', globals) + await expect(`str.replace-all 'hello hello' 'hello' 'hi'`).toEvaluateTo('hi hi') }) test('slice extracts substring', async () => { - await expect(`str.slice 'hello' 1 3`).toEvaluateTo('el', globals) - await expect(`str.slice 'hello' 2 null`).toEvaluateTo('llo', globals) + await expect(`str.slice 'hello' 1 3`).toEvaluateTo('el') + await expect(`str.slice 'hello' 2 null`).toEvaluateTo('llo') }) test('repeat repeats string', async () => { - await expect(`str.repeat 'ha' 3`).toEvaluateTo('hahaha', globals) + await expect(`str.repeat 'ha' 3`).toEvaluateTo('hahaha') }) test('pad-start pads beginning', async () => { - await expect(`str.pad-start '5' 3 '0'`).toEvaluateTo('005', globals) + await expect(`str.pad-start '5' 3 '0'`).toEvaluateTo('005') }) test('pad-end pads end', async () => { - await expect(`str.pad-end '5' 3 '0'`).toEvaluateTo('500', globals) + await expect(`str.pad-end '5' 3 '0'`).toEvaluateTo('500') }) test('lines splits by newlines', async () => { - await expect(`str.lines 'a\\nb\\nc'`).toEvaluateTo(['a', 'b', 'c'], globals) + await expect(`str.lines 'a\\nb\\nc'`).toEvaluateTo(['a', 'b', 'c']) }) test('chars splits into characters', async () => { - await expect(`str.chars 'abc'`).toEvaluateTo(['a', 'b', 'c'], globals) + await expect(`str.chars 'abc'`).toEvaluateTo(['a', 'b', 'c']) }) test('index-of finds substring position', async () => { - await expect(`str.index-of 'hello world' 'world'`).toEvaluateTo(6, globals) - await expect(`str.index-of 'hello' 'bye'`).toEvaluateTo(-1, globals) + await expect(`str.index-of 'hello world' 'world'`).toEvaluateTo(6) + await expect(`str.index-of 'hello' 'bye'`).toEvaluateTo(-1) }) test('last-index-of finds last occurrence', async () => { - await expect(`str.last-index-of 'hello hello' 'hello'`).toEvaluateTo(6, globals) + await expect(`str.last-index-of 'hello hello' 'hello'`).toEvaluateTo(6) }) }) describe('boolean logic', () => { test('not negates value', async () => { - await expect(`not true`).toEvaluateTo(false, globals) - await expect(`not false`).toEvaluateTo(true, globals) - await expect(`not 42`).toEvaluateTo(false, globals) - await expect(`not null`).toEvaluateTo(true, globals) + await expect(`not true`).toEvaluateTo(false) + await expect(`not false`).toEvaluateTo(true) + await expect(`not 42`).toEvaluateTo(false) + await expect(`not null`).toEvaluateTo(true) }) }) describe('utilities', () => { test('inc increments by 1', async () => { - await expect(`inc 5`).toEvaluateTo(6, globals) - await expect(`inc -1`).toEvaluateTo(0, globals) + await expect(`inc 5`).toEvaluateTo(6) + await expect(`inc -1`).toEvaluateTo(0) }) test('dec decrements by 1', async () => { - await expect(`dec 5`).toEvaluateTo(4, globals) - await expect(`dec 0`).toEvaluateTo(-1, globals) + await expect(`dec 5`).toEvaluateTo(4) + await expect(`dec 0`).toEvaluateTo(-1) }) test('identity returns value as-is', async () => { - await expect(`identity 42`).toEvaluateTo(42, globals) - await expect(`identity 'hello'`).toEvaluateTo('hello', globals) + await expect(`identity 42`).toEvaluateTo(42) + await expect(`identity 'hello'`).toEvaluateTo('hello') }) }) describe('collections', () => { test('length', async () => { - await expect(`length 'hello'`).toEvaluateTo(5, globals) - await expect(`length [1 2 3]`).toEvaluateTo(3, globals) - await expect(`length [a=1 b=2]`).toEvaluateTo(2, globals) + await expect(`length 'hello'`).toEvaluateTo(5) + await expect(`length [1 2 3]`).toEvaluateTo(3) + await expect(`length [a=1 b=2]`).toEvaluateTo(2) }) test('length throws on invalid types', async () => { - await expect(`try: length 42 catch e: 'error' end`).toEvaluateTo('error', globals) - await expect(`try: length true catch e: 'error' end`).toEvaluateTo('error', globals) - await expect(`try: length null catch e: 'error' end`).toEvaluateTo('error', globals) + await expect(`try: length 42 catch e: 'error' end`).toEvaluateTo('error') + await expect(`try: length true catch e: 'error' end`).toEvaluateTo('error') + await expect(`try: length null catch e: 'error' end`).toEvaluateTo('error') }) test('literal array creates array from arguments', async () => { - await expect(`[ 1 2 3 ]`).toEvaluateTo([1, 2, 3], globals) - await expect(`['a' 'b']`).toEvaluateTo(['a', 'b'], globals) - await expect(`[]`).toEvaluateTo([], globals) + await expect(`[ 1 2 3 ]`).toEvaluateTo([1, 2, 3]) + await expect(`['a' 'b']`).toEvaluateTo(['a', 'b']) + await expect(`[]`).toEvaluateTo([]) }) test('literal dict creates object from named arguments', async () => { - await expect(`[ a=1 b=2 ]`).toEvaluateTo({ a: 1, b: 2 }, globals) - await expect(`[=]`).toEvaluateTo({}, globals) + await expect(`[ a=1 b=2 ]`).toEvaluateTo({ a: 1, b: 2 }) + await expect(`[=]`).toEvaluateTo({}) }) test('at retrieves element at index', async () => { - await expect(`at [10 20 30] 0`).toEvaluateTo(10, globals) - await expect(`at [10 20 30] 2`).toEvaluateTo(30, globals) + await expect(`at [10 20 30] 0`).toEvaluateTo(10) + await expect(`at [10 20 30] 2`).toEvaluateTo(30) }) test('at retrieves property from object', async () => { - await expect(`at [name='test'] 'name'`).toEvaluateTo('test', globals) + await expect(`at [name='test'] 'name'`).toEvaluateTo('test') }) test('slice extracts array subset', async () => { - await expect(`list.slice [1 2 3 4 5] 1 3`).toEvaluateTo([2, 3], globals) - await expect(`list.slice [1 2 3 4 5] 2 5`).toEvaluateTo([3, 4, 5], globals) + await expect(`list.slice [1 2 3 4 5] 1 3`).toEvaluateTo([2, 3]) + await expect(`list.slice [1 2 3 4 5] 2 5`).toEvaluateTo([3, 4, 5]) }) test('range creates number sequence', async () => { - await expect(`range 0 5`).toEvaluateTo([0, 1, 2, 3, 4, 5], globals) - await expect(`range 3 6`).toEvaluateTo([3, 4, 5, 6], globals) + await expect(`range 0 5`).toEvaluateTo([0, 1, 2, 3, 4, 5]) + await expect(`range 3 6`).toEvaluateTo([3, 4, 5, 6]) }) test('range with single argument starts from 0', async () => { - await expect(`range 3 null`).toEvaluateTo([0, 1, 2, 3], globals) - await expect(`range 0 null`).toEvaluateTo([0], globals) + await expect(`range 3 null`).toEvaluateTo([0, 1, 2, 3]) + await expect(`range 0 null`).toEvaluateTo([0]) }) test('empty? checks if list, dict, string is empty', async () => { - await expect(`empty? []`).toEvaluateTo(true, globals) - await expect(`empty? [1]`).toEvaluateTo(false, globals) + await expect(`empty? []`).toEvaluateTo(true) + await expect(`empty? [1]`).toEvaluateTo(false) - await expect(`empty? [=]`).toEvaluateTo(true, globals) - await expect(`empty? [a=true]`).toEvaluateTo(false, globals) + await expect(`empty? [=]`).toEvaluateTo(true) + await expect(`empty? [a=true]`).toEvaluateTo(false) - await expect(`empty? ''`).toEvaluateTo(true, globals) - await expect(`empty? 'cat'`).toEvaluateTo(false, globals) - await expect(`empty? meow`).toEvaluateTo(false, globals) + await expect(`empty? ''`).toEvaluateTo(true) + await expect(`empty? 'cat'`).toEvaluateTo(false) + await expect(`empty? meow`).toEvaluateTo(false) }) test('list.filter keeps matching elements', async () => { @@ -190,7 +190,7 @@ describe('collections', () => { x == 3 or x == 4 or x == 5 end list.filter [1 2 3 4 5] is-positive - `).toEvaluateTo([3, 4, 5], globals) + `).toEvaluateTo([3, 4, 5]) }) test('list.reduce accumulates values', async () => { @@ -199,7 +199,7 @@ describe('collections', () => { acc + x end list.reduce [1 2 3 4] add 0 - `).toEvaluateTo(10, globals) + `).toEvaluateTo(10) }) test('list.find returns first match', async () => { @@ -208,139 +208,139 @@ describe('collections', () => { x == 4 end list.find [1 2 4 5] is-four - `).toEvaluateTo(4, globals) + `).toEvaluateTo(4) }) test('list.find returns null if no match', async () => { await expect(` is-ten = do x: x == 10 end list.find [1 2 3] is-ten - `).toEvaluateTo(null, globals) + `).toEvaluateTo(null) }) test('list.empty? checks if list is empty', async () => { - await expect(`list.empty? []`).toEvaluateTo(true, globals) - await expect(`list.empty? [1]`).toEvaluateTo(false, globals) + await expect(`list.empty? []`).toEvaluateTo(true) + await expect(`list.empty? [1]`).toEvaluateTo(false) }) test('list.contains? checks for element', async () => { - await expect(`list.contains? [1 2 3] 2`).toEvaluateTo(true, globals) - await expect(`list.contains? [1 2 3] 5`).toEvaluateTo(false, globals) + await expect(`list.contains? [1 2 3] 2`).toEvaluateTo(true) + await expect(`list.contains? [1 2 3] 5`).toEvaluateTo(false) }) test('list.reverse reverses array', async () => { - await expect(`list.reverse [1 2 3]`).toEvaluateTo([3, 2, 1], globals) + await expect(`list.reverse [1 2 3]`).toEvaluateTo([3, 2, 1]) }) test('list.concat combines arrays', async () => { - await expect(`list.concat [1 2] [3 4]`).toEvaluateTo([1, 2, 3, 4], globals) + await expect(`list.concat [1 2] [3 4]`).toEvaluateTo([1, 2, 3, 4]) }) test('list.flatten flattens nested arrays', async () => { - await expect(`list.flatten [[1 2] [3 4]] 1`).toEvaluateTo([1, 2, 3, 4], globals) + await expect(`list.flatten [[1 2] [3 4]] 1`).toEvaluateTo([1, 2, 3, 4]) }) test('list.unique removes duplicates', async () => { - await expect(`list.unique [1 2 2 3 1]`).toEvaluateTo([1, 2, 3], globals) + await expect(`list.unique [1 2 2 3 1]`).toEvaluateTo([1, 2, 3]) }) test('list.zip combines two arrays', async () => { - await expect(`list.zip [1 2] [3 4]`).toEvaluateTo([[1, 3], [2, 4]], globals) + await expect(`list.zip [1 2] [3 4]`).toEvaluateTo([[1, 3], [2, 4]]) }) test('list.first returns first element', async () => { - await expect(`list.first [1 2 3]`).toEvaluateTo(1, globals) - await expect(`list.first []`).toEvaluateTo(null, globals) + await expect(`list.first [1 2 3]`).toEvaluateTo(1) + await expect(`list.first []`).toEvaluateTo(null) }) test('list.last returns last element', async () => { - await expect(`list.last [1 2 3]`).toEvaluateTo(3, globals) - await expect(`list.last []`).toEvaluateTo(null, globals) + await expect(`list.last [1 2 3]`).toEvaluateTo(3) + await expect(`list.last []`).toEvaluateTo(null) }) test('list.rest returns all but first', async () => { - await expect(`list.rest [1 2 3]`).toEvaluateTo([2, 3], globals) + await expect(`list.rest [1 2 3]`).toEvaluateTo([2, 3]) }) test('list.take returns first n elements', async () => { - await expect(`list.take [1 2 3 4 5] 3`).toEvaluateTo([1, 2, 3], globals) + await expect(`list.take [1 2 3 4 5] 3`).toEvaluateTo([1, 2, 3]) }) test('list.drop skips first n elements', async () => { - await expect(`list.drop [1 2 3 4 5] 2`).toEvaluateTo([3, 4, 5], globals) + await expect(`list.drop [1 2 3 4 5] 2`).toEvaluateTo([3, 4, 5]) }) test('list.append adds to end', async () => { - await expect(`list.append [1 2] 3`).toEvaluateTo([1, 2, 3], globals) + await expect(`list.append [1 2] 3`).toEvaluateTo([1, 2, 3]) }) test('list.prepend adds to start', async () => { - await expect(`list.prepend [2 3] 1`).toEvaluateTo([1, 2, 3], globals) + await expect(`list.prepend [2 3] 1`).toEvaluateTo([1, 2, 3]) }) test('list.index-of finds element index', async () => { - await expect(`list.index-of [1 2 3] 2`).toEvaluateTo(1, globals) - await expect(`list.index-of [1 2 3] 5`).toEvaluateTo(-1, globals) + await expect(`list.index-of [1 2 3] 2`).toEvaluateTo(1) + await expect(`list.index-of [1 2 3] 5`).toEvaluateTo(-1) }) test('list.push adds to end and mutates array', async () => { - await expect(`arr = [1 2]; list.push arr 3; arr`).toEvaluateTo([1, 2, 3], globals) + await expect(`arr = [1 2]; list.push arr 3; arr`).toEvaluateTo([1, 2, 3]) }) test('list.push returns the size of the array', async () => { - await expect(`arr = [1 2]; arr | list.push 3`).toEvaluateTo(3, globals) + await expect(`arr = [1 2]; arr | list.push 3`).toEvaluateTo(3) }) test('list.pop removes from end and mutates array', async () => { - await expect(`arr = [1 2 3]; list.pop arr; arr`).toEvaluateTo([1, 2], globals) + await expect(`arr = [1 2 3]; list.pop arr; arr`).toEvaluateTo([1, 2]) }) test('list.pop returns removed element', async () => { - await expect(`list.pop [1 2 3]`).toEvaluateTo(3, globals) + await expect(`list.pop [1 2 3]`).toEvaluateTo(3) }) test('list.pop returns null for empty array', async () => { - await expect(`list.pop []`).toEvaluateTo(null, globals) + await expect(`list.pop []`).toEvaluateTo(null) }) test('list.shift removes from start and mutates array', async () => { - await expect(`arr = [1 2 3]; list.shift arr; arr`).toEvaluateTo([2, 3], globals) + await expect(`arr = [1 2 3]; list.shift arr; arr`).toEvaluateTo([2, 3]) }) test('list.shift returns removed element', async () => { - await expect(`list.shift [1 2 3]`).toEvaluateTo(1, globals) + await expect(`list.shift [1 2 3]`).toEvaluateTo(1) }) test('list.shift returns null for empty array', async () => { - await expect(`list.shift []`).toEvaluateTo(null, globals) + await expect(`list.shift []`).toEvaluateTo(null) }) test('list.unshift adds to start and mutates array', async () => { - await expect(`arr = [2 3]; list.unshift arr 1; arr`).toEvaluateTo([1, 2, 3], globals) + await expect(`arr = [2 3]; list.unshift arr 1; arr`).toEvaluateTo([1, 2, 3]) }) test('list.unshift returns the length of the array', async () => { - await expect(`arr = [2 3]; arr | list.unshift 1`).toEvaluateTo(3, globals) + await expect(`arr = [2 3]; arr | list.unshift 1`).toEvaluateTo(3) }) test('list.splice removes elements and mutates array', async () => { - await expect(`arr = [1 2 3 4 5]; list.splice arr 1 2; arr`).toEvaluateTo([1, 4, 5], globals) + await expect(`arr = [1 2 3 4 5]; list.splice arr 1 2; arr`).toEvaluateTo([1, 4, 5]) }) test('list.splice returns removed elements', async () => { - await expect(`list.splice [1 2 3 4 5] 1 2`).toEvaluateTo([2, 3], globals) + await expect(`list.splice [1 2 3 4 5] 1 2`).toEvaluateTo([2, 3]) }) test('list.splice from start', async () => { - await expect(`list.splice [1 2 3 4 5] 0 2`).toEvaluateTo([1, 2], globals) + await expect(`list.splice [1 2 3 4 5] 0 2`).toEvaluateTo([1, 2]) }) test('list.splice to end', async () => { - await expect(`arr = [1 2 3 4 5]; list.splice arr 3 2; arr`).toEvaluateTo([1, 2, 3], globals) + await expect(`arr = [1 2 3 4 5]; list.splice arr 3 2; arr`).toEvaluateTo([1, 2, 3]) }) test('list.sort with no callback sorts ascending', async () => { - await expect(`list.sort [3 1 4 1 5] null`).toEvaluateTo([1, 1, 3, 4, 5], globals) + await expect(`list.sort [3 1 4 1 5] null`).toEvaluateTo([1, 1, 3, 4, 5]) }) test('list.sort with callback sorts using comparator', async () => { @@ -349,7 +349,7 @@ describe('collections', () => { b - a end list.sort [3 1 4 1 5] desc - `).toEvaluateTo([5, 4, 3, 1, 1], globals) + `).toEvaluateTo([5, 4, 3, 1, 1]) }) test('list.sort with callback for strings by length', async () => { @@ -358,52 +358,52 @@ describe('collections', () => { (length a) - (length b) end list.sort ['cat' 'a' 'dog' 'elephant'] by-length - `).toEvaluateTo(['a', 'cat', 'dog', 'elephant'], globals) + `).toEvaluateTo(['a', 'cat', 'dog', 'elephant']) }) test('list.any? checks if any element matches', async () => { await expect(` gt-three = do x: x > 3 end list.any? [1 2 4 5] gt-three - `).toEvaluateTo(true, globals) + `).toEvaluateTo(true) await expect(` gt-ten = do x: x > 10 end list.any? [1 2 3] gt-ten - `).toEvaluateTo(false, globals) + `).toEvaluateTo(false) }) test('list.all? checks if all elements match', async () => { await expect(` positive = do x: x > 0 end list.all? [1 2 3] positive - `).toEvaluateTo(true, globals) + `).toEvaluateTo(true) await expect(` positive = do x: x > 0 end list.all? [1 -2 3] positive - `).toEvaluateTo(false, globals) + `).toEvaluateTo(false) }) test('list.sum adds all numbers', async () => { - await expect(`list.sum [1 2 3 4]`).toEvaluateTo(10, globals) - await expect(`list.sum []`).toEvaluateTo(0, globals) + await expect(`list.sum [1 2 3 4]`).toEvaluateTo(10) + await expect(`list.sum []`).toEvaluateTo(0) }) test('list.count counts matching elements', async () => { await expect(` gt-two = do x: x > 2 end list.count [1 2 3 4 5] gt-two - `).toEvaluateTo(3, globals) + `).toEvaluateTo(3) }) test('list.partition splits array by predicate', async () => { await expect(` gt-two = do x: x > 2 end list.partition [1 2 3 4 5] gt-two - `).toEvaluateTo([[3, 4, 5], [1, 2]], globals) + `).toEvaluateTo([[3, 4, 5], [1, 2]]) }) test('list.compact removes null values', async () => { - await expect(`list.compact [1 null 2 null 3]`).toEvaluateTo([1, 2, 3], globals) + await expect(`list.compact [1 null 2 null 3]`).toEvaluateTo([1, 2, 3]) }) test('list.group-by groups by key function', async () => { @@ -416,7 +416,7 @@ describe('collections', () => { end end list.group-by ['a' 1 'b' 2] get-type - `).toEvaluateTo({ str: ['a', 'b'], num: [1, 2] }, globals) + `).toEvaluateTo({ str: ['a', 'b'], num: [1, 2] }) }) }) @@ -425,14 +425,14 @@ describe('enumerables', () => { await expect(` double = do x: x * 2 end list.map [1 2 3] double - `).toEvaluateTo([2, 4, 6], globals) + `).toEvaluateTo([2, 4, 6]) }) test('map handles empty array', async () => { await expect(` double = do x: x * 2 end list.map [] double - `).toEvaluateTo([], globals) + `).toEvaluateTo([]) }) test('each iterates over array', async () => { @@ -441,14 +441,14 @@ describe('enumerables', () => { await expect(` double = do x: x * 2 end each [1 2 3] double - `).toEvaluateTo([1, 2, 3], globals) + `).toEvaluateTo([1, 2, 3]) }) test('each handles empty array', async () => { await expect(` fn = do x: x end each [] fn - `).toEvaluateTo([], globals) + `).toEvaluateTo([]) }) }) @@ -460,7 +460,7 @@ describe('dict operations', () => { const { setGlobals } = await import('#parser/tokenizer') setGlobals(Object.keys(globals)) const c = new Compiler('dict.keys [a=1 b=2 c=3]') - const r = await run(c.bytecode, globals) + const r = await run(c.bytecode) return fromValue(r) })() // Check that all expected keys are present (order may vary) @@ -474,7 +474,7 @@ describe('dict operations', () => { const { setGlobals } = await import('#parser/tokenizer') setGlobals(Object.keys(globals)) const c = new Compiler('dict.values [a=1 b=2]') - const r = await run(c.bytecode, globals) + const r = await run(c.bytecode) return fromValue(r) })() // Check that all expected values are present (order may vary) @@ -482,124 +482,124 @@ describe('dict operations', () => { }) test('dict.has? checks for key', async () => { - await expect(`dict.has? [a=1 b=2] 'a'`).toEvaluateTo(true, globals) - await expect(`dict.has? [a=1 b=2] 'c'`).toEvaluateTo(false, globals) + await expect(`dict.has? [a=1 b=2] 'a'`).toEvaluateTo(true) + await expect(`dict.has? [a=1 b=2] 'c'`).toEvaluateTo(false) }) test('dict.get retrieves value with default', async () => { - await expect(`dict.get [a=1] 'a' 0`).toEvaluateTo(1, globals) - await expect(`dict.get [a=1] 'b' 99`).toEvaluateTo(99, globals) + await expect(`dict.get [a=1] 'a' 0`).toEvaluateTo(1) + await expect(`dict.get [a=1] 'b' 99`).toEvaluateTo(99) }) test('dict.set sets value', async () => { - await expect(`map = [a=1]; dict.set map 'b' 99; map.b`).toEvaluateTo(99, globals) - await expect(`map = [a=1]; dict.set map 'a' 100; map.a`).toEvaluateTo(100, globals) + await expect(`map = [a=1]; dict.set map 'b' 99; map.b`).toEvaluateTo(99) + await expect(`map = [a=1]; dict.set map 'a' 100; map.a`).toEvaluateTo(100) }) test('dict.empty? checks if dict is empty', async () => { - await expect(`dict.empty? [=]`).toEvaluateTo(true, globals) - await expect(`dict.empty? [a=1]`).toEvaluateTo(false, globals) + await expect(`dict.empty? [=]`).toEvaluateTo(true) + await expect(`dict.empty? [a=1]`).toEvaluateTo(false) }) test('dict.merge combines dicts', async () => { - await expect(`dict.merge [a=1] [b=2]`).toEvaluateTo({ a: 1, b: 2 }, globals) + await expect(`dict.merge [a=1] [b=2]`).toEvaluateTo({ a: 1, b: 2 }) }) test('dict.map transforms values', async () => { await expect(` double = do v k: v * 2 end dict.map [a=1 b=2] double - `).toEvaluateTo({ a: 2, b: 4 }, globals) + `).toEvaluateTo({ a: 2, b: 4 }) }) test('dict.filter keeps matching entries', async () => { await expect(` gt-one = do v k: v > 1 end dict.filter [a=1 b=2 c=3] gt-one - `).toEvaluateTo({ b: 2, c: 3 }, globals) + `).toEvaluateTo({ b: 2, c: 3 }) }) test('dict.from-entries creates dict from array', async () => { - await expect(`dict.from-entries [['a' 1] ['b' 2]]`).toEvaluateTo({ a: 1, b: 2 }, globals) + await expect(`dict.from-entries [['a' 1] ['b' 2]]`).toEvaluateTo({ a: 1, b: 2 }) }) }) describe('math operations', () => { test('math.abs returns absolute value', async () => { - await expect(`math.abs -5`).toEvaluateTo(5, globals) - await expect(`math.abs 5`).toEvaluateTo(5, globals) + await expect(`math.abs -5`).toEvaluateTo(5) + await expect(`math.abs 5`).toEvaluateTo(5) }) test('math.floor rounds down', async () => { - await expect(`math.floor 3.7`).toEvaluateTo(3, globals) + await expect(`math.floor 3.7`).toEvaluateTo(3) }) test('math.ceil rounds up', async () => { - await expect(`math.ceil 3.2`).toEvaluateTo(4, globals) + await expect(`math.ceil 3.2`).toEvaluateTo(4) }) test('math.round rounds to nearest', async () => { - await expect(`math.round 3.4`).toEvaluateTo(3, globals) - await expect(`math.round 3.6`).toEvaluateTo(4, globals) + await expect(`math.round 3.4`).toEvaluateTo(3) + await expect(`math.round 3.6`).toEvaluateTo(4) }) test('math.min returns minimum', async () => { - await expect(`math.min 5 2 8 1`).toEvaluateTo(1, globals) + await expect(`math.min 5 2 8 1`).toEvaluateTo(1) }) test('math.max returns maximum', async () => { - await expect(`math.max 5 2 8 1`).toEvaluateTo(8, globals) + await expect(`math.max 5 2 8 1`).toEvaluateTo(8) }) test('math.pow computes power', async () => { - await expect(`math.pow 2 3`).toEvaluateTo(8, globals) + await expect(`math.pow 2 3`).toEvaluateTo(8) }) test('math.sqrt computes square root', async () => { - await expect(`math.sqrt 16`).toEvaluateTo(4, globals) + await expect(`math.sqrt 16`).toEvaluateTo(4) }) test('math.even? checks if even', async () => { - await expect(`math.even? 4`).toEvaluateTo(true, globals) - await expect(`math.even? 5`).toEvaluateTo(false, globals) + await expect(`math.even? 4`).toEvaluateTo(true) + await expect(`math.even? 5`).toEvaluateTo(false) }) test('math.odd? checks if odd', async () => { - await expect(`math.odd? 5`).toEvaluateTo(true, globals) - await expect(`math.odd? 4`).toEvaluateTo(false, globals) + await expect(`math.odd? 5`).toEvaluateTo(true) + await expect(`math.odd? 4`).toEvaluateTo(false) }) test('math.positive? checks if positive', async () => { - await expect(`math.positive? 5`).toEvaluateTo(true, globals) - await expect(`math.positive? -5`).toEvaluateTo(false, globals) - await expect(`math.positive? 0`).toEvaluateTo(false, globals) + await expect(`math.positive? 5`).toEvaluateTo(true) + await expect(`math.positive? -5`).toEvaluateTo(false) + await expect(`math.positive? 0`).toEvaluateTo(false) }) test('math.negative? checks if negative', async () => { - await expect(`math.negative? -5`).toEvaluateTo(true, globals) - await expect(`math.negative? 5`).toEvaluateTo(false, globals) + await expect(`math.negative? -5`).toEvaluateTo(true) + await expect(`math.negative? 5`).toEvaluateTo(false) }) test('math.zero? checks if zero', async () => { - await expect(`math.zero? 0`).toEvaluateTo(true, globals) - await expect(`math.zero? 5`).toEvaluateTo(false, globals) + await expect(`math.zero? 0`).toEvaluateTo(true) + await expect(`math.zero? 5`).toEvaluateTo(false) }) test('math.clamp restricts value to range', async () => { - await expect(`math.clamp 5 0 10`).toEvaluateTo(5, globals) - await expect(`math.clamp -5 0 10`).toEvaluateTo(0, globals) - await expect(`math.clamp 15 0 10`).toEvaluateTo(10, globals) + await expect(`math.clamp 5 0 10`).toEvaluateTo(5) + await expect(`math.clamp -5 0 10`).toEvaluateTo(0) + await expect(`math.clamp 15 0 10`).toEvaluateTo(10) }) test('math.sign returns sign of number', async () => { - await expect(`math.sign 5`).toEvaluateTo(1, globals) - await expect(`math.sign -5`).toEvaluateTo(-1, globals) - await expect(`math.sign 0`).toEvaluateTo(0, globals) + await expect(`math.sign 5`).toEvaluateTo(1) + await expect(`math.sign -5`).toEvaluateTo(-1) + await expect(`math.sign 0`).toEvaluateTo(0) }) test('math.trunc truncates decimal', async () => { - await expect(`math.trunc 3.7`).toEvaluateTo(3, globals) - await expect(`math.trunc -3.7`).toEvaluateTo(-3, globals) + await expect(`math.trunc 3.7`).toEvaluateTo(3) + await expect(`math.trunc -3.7`).toEvaluateTo(-3) }) }) From afaedeea23b7d3e874fc9c370340ace31d8e9b11 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Thu, 6 Nov 2025 21:39:51 -0800 Subject: [PATCH 3/4] probably using list.sort is okay? --- src/prelude/tests/prelude.test.ts | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/src/prelude/tests/prelude.test.ts b/src/prelude/tests/prelude.test.ts index 2794255..04ceb8b 100644 --- a/src/prelude/tests/prelude.test.ts +++ b/src/prelude/tests/prelude.test.ts @@ -454,31 +454,11 @@ describe('enumerables', () => { describe('dict operations', () => { test('dict.keys returns all keys', async () => { - const result = await (async () => { - const { Compiler } = await import('#compiler/compiler') - const { run, fromValue } = await import('reefvm') - const { setGlobals } = await import('#parser/tokenizer') - setGlobals(Object.keys(globals)) - const c = new Compiler('dict.keys [a=1 b=2 c=3]') - const r = await run(c.bytecode) - return fromValue(r) - })() - // Check that all expected keys are present (order may vary) - expect(result.sort()).toEqual(['a', 'b', 'c']) + await expect(`dict.keys [a=1 b=2 c=3] | list.sort`).toEvaluateTo(['a', 'b', 'c'].sort()) }) test('dict.values returns all values', async () => { - const result = await (async () => { - const { Compiler } = await import('#compiler/compiler') - const { run, fromValue } = await import('reefvm') - const { setGlobals } = await import('#parser/tokenizer') - setGlobals(Object.keys(globals)) - const c = new Compiler('dict.values [a=1 b=2]') - const r = await run(c.bytecode) - return fromValue(r) - })() - // Check that all expected values are present (order may vary) - expect(result.sort()).toEqual([1, 2]) + await expect('dict.values [a=1 b=2] | list.sort').toEvaluateTo([1, 2].sort()) }) test('dict.has? checks for key', async () => { @@ -489,6 +469,7 @@ describe('dict operations', () => { test('dict.get retrieves value with default', async () => { await expect(`dict.get [a=1] 'a' 0`).toEvaluateTo(1) await expect(`dict.get [a=1] 'b' 99`).toEvaluateTo(99) + await expect(`dict.get [a=1] 'b'`).toEvaluateTo(null) }) test('dict.set sets value', async () => { From 1082cc1281d2781764e8f3d4a832a3916caf00db Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Fri, 7 Nov 2025 07:27:20 -0800 Subject: [PATCH 4/4] Forgot to set globals in server --- vscode-extension/server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vscode-extension/server/src/server.ts b/vscode-extension/server/src/server.ts index 194b35e..1df7086 100644 --- a/vscode-extension/server/src/server.ts +++ b/vscode-extension/server/src/server.ts @@ -11,6 +11,8 @@ import { ProposedFeatures, CompletionItemKind, } from 'vscode-languageserver/node' +import { setGlobals } from '../../../src/parser/tokenizer' +import { globals } from '../../../src/prelude' const connection = createConnection(ProposedFeatures.all) const documents = new TextDocuments(TextDocument) @@ -31,10 +33,7 @@ connection.onRequest('shrimp/bytecode', handleBytecode) // Start listening connection.listen() -// ============================================================================ // Handler implementations -// ============================================================================ - function handleInitialize(): InitializeResult { connection.console.log('🦐 Server initialized with capabilities') const result: InitializeResult = { @@ -85,6 +84,7 @@ function handleParseTree(params: { uri: string }) { if (!document) return 'Document not found' const text = document.getText() + setGlobals(Object.keys(globals)) const tree = parser.parse(text) const cursor = tree.cursor()