about summary refs log tree commit diff stats
path: root/js/baba-yaga/tests/with-when-expressions.test.js
blob: af14d104302cbaf1134005e7e3db5c7b1e977f54 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import assert from 'assert';
import { createLexer } from '../src/core/lexer.js';
import { createParser } from '../src/core/parser.js';
import { createInterpreter } from '../src/core/interpreter.js';

function interpret(code) {
  const lexer = createLexer(code);
  const tokens = lexer.allTokens();
  const parser = createParser(tokens);
  const ast = parser.parse();
  const interpreter = createInterpreter(ast);
  interpreter.interpret();
  return interpreter;
}

describe('with header: when expressions', () => {
  it('evaluates simple single-line when expressions', () => {
    const code = `
      test : x ->
        with (status : when x is 0 then "zero" _ then "other";) -> status;
      result : test 0;
    `;
    const itp = interpret(code);
    assert.strictEqual(itp.scope.get('result'), 'zero');
  });

  it('evaluates multi-line when expressions', () => {
    const code = `
      test : x ->
        with (
          status : when x is
            0 then "zero"
            _ then when (x < 10) is
              true then "small"
              _ then "large";
        ) -> status;
      result1 : test 0;
      result2 : test 5;
      result3 : test 15;
    `;
    const itp = interpret(code);
    assert.strictEqual(itp.scope.get('result1'), 'zero');
    assert.strictEqual(itp.scope.get('result2'), 'small');
    assert.strictEqual(itp.scope.get('result3'), 'large');
  });

  it('evaluates complex when expressions with pattern guards', () => {
    const code = `
      test : x ->
        with (
          category : when x is
            n if (n < 0) then "negative"
            0 then "zero"
            n if (n > 10) then "large"
            _ then "small";
        ) -> category;
      result1 : test -5;
      result2 : test 0;
      result3 : test 5;
      result4 : test 15;
    `;
    const itp = interpret(code);
    assert.strictEqual(itp.scope.get('result1'), 'negative');
    assert.strictEqual(itp.scope.get('result2'), 'zero');
    assert.strictEqual(itp.scope.get('result3'), 'small');
    assert.strictEqual(itp.scope.get('result4'), 'large');
  });

  it('evaluates mixed when expressions with other types', () => {
    const code = `
      test : x ->
        with (
          num : x + 1;
          category : when x is
            0 then "zero"
            _ then when (x < 10) is
              true then "small"
              _ then "large";
          isValid : x > 0;
        ) -> { num: num, category: category, isValid: isValid };
      result : test 5;
    `;
    const itp = interpret(code);
    const result = itp.scope.get('result');
    assert.strictEqual(result.num.value, 6);
    assert.strictEqual(result.category, 'small');
    assert.strictEqual(result.isValid, true);
  });

  it('evaluates deeply nested when expressions', () => {
    const code = `
      test : x ->
        with (
          status : when x is
            0 then "zero"
            _ then when (x < 10) is
              true then "small"
              _ then when (x < 100) is
                true then "medium"
                _ then when (x < 1000) is
                  true then "large"
                  _ then "huge";
        ) -> status;
      result1 : test 0;
      result2 : test 5;
      result3 : test 50;
      result4 : test 500;
      result5 : test 5000;
    `;
    const itp = interpret(code);
    assert.strictEqual(itp.scope.get('result1'), 'zero');
    assert.strictEqual(itp.scope.get('result2'), 'small');
    assert.strictEqual(itp.scope.get('result3'), 'medium');
    assert.strictEqual(itp.scope.get('result4'), 'large');
    assert.strictEqual(itp.scope.get('result5'), 'huge');
  });

  it('works with arithmetic expressions in when conditions', () => {
    const code = `
      test : x ->
        with (
          status : when (x + 1) is
            1 then "zero-based"
            _ then when ((x * 2) > 10) is
              true then "large"
              _ then "small";
        ) -> status;
      result1 : test 0;
      result2 : test 3;
      result3 : test 6;
    `;
    const itp = interpret(code);
    assert.strictEqual(itp.scope.get('result1'), 'zero-based');
    assert.strictEqual(itp.scope.get('result2'), 'small');
    assert.strictEqual(itp.scope.get('result3'), 'large');
  });

  it('works with function calls in when conditions', () => {
    const code = `
      test : list ->
        with (
          len : length list;
          status : when len is
            0 then "empty"
            _ then when (len > 5) is
              true then "long"
              _ then "short";
        ) -> status;
      result1 : test [];
      result2 : test [1, 2, 3];
      result3 : test [1, 2, 3, 4, 5, 6];
    `;
    const itp = interpret(code);
    assert.strictEqual(itp.scope.get('result1'), 'empty');
    assert.strictEqual(itp.scope.get('result2'), 'short');
    assert.strictEqual(itp.scope.get('result3'), 'long');
  });
});