• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

visgl / luma.gl / 26178691674

20 May 2026 05:24PM UTC coverage: 74.942% (+0.09%) from 74.85%
26178691674

push

github

web-flow
feat(gpgpu): Consolidate arithmetic operations (#2630)

7494 of 11282 branches covered (66.42%)

Branch coverage included in aggregate %.

281 of 344 new or added lines in 30 files covered. (81.69%)

26 existing lines in 5 files now uncovered.

16166 of 20289 relevant lines covered (79.68%)

1206.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.95
/modules/gpgpu/src/utils/expression.ts
1
// luma.gl
2
// SPDX-License-Identifier: MIT
3
// Copyright (c) vis.gl contributors
4

5
/** JSON-friendly scalar expression tree for elementwise row transforms. */
6
export type ExpressionLiteral = number | number[];
7

8
export type Expression<OpT extends string = string> =
9
  | {kind: 'input'; name: string}
10
  | {kind: 'literal'; value: ExpressionLiteral}
11
  | {kind: 'call'; op: OpT; args: Expression<OpT>[]};
12

13
/** Operation metadata used to validate and lower expression nodes to GLSL calls. */
14
export type ExpressionOperation = {
15
  arity: number;
16
  symbol: string;
17
};
18

19
export type ExpressionOperations<OpT extends string = string> = Record<OpT, ExpressionOperation>;
20

21
export type CompileExpressionOptions<OpT extends string = string> = {
22
  /** Operation metadata keyed by expression op. */
23
  operations: ExpressionOperations<OpT>;
24
  /** Names that can be referenced by `input` nodes. */
25
  inputs: Record<string, {size: number}>;
26
  /** Current output lane index used when reading elementwise inputs. */
27
  laneIndex: number;
28
  /** Formats an in-bounds input reference. */
29
  formatInput: (name: string) => string;
30
  /** Formats an out-of-bounds input reference. */
31
  formatOutOfBoundsInput: (name: string) => string;
32
  /** Formats a numeric literal for the target shading language. */
33
  formatLiteral: (value: ExpressionLiteral) => string;
34
  /** Formats a call expression using the target shading language syntax. */
35
  formatCall: (symbol: string, args: string[]) => string;
36
};
37

38
/**
39
 * Validates an expression tree against known operations and available inputs.
40
 *
41
 * Throws a descriptive error if a node is malformed.
42
 */
43
export function validateExpression<OpT extends string>(
44
  expression: Expression<OpT>,
45
  {
46
    operations,
47
    inputs
48
  }: {
49
    operations: ExpressionOperations<OpT>;
50
    inputs: Record<string, {size: number}>;
51
  }
52
): void {
53
  switch (expression.kind) {
806!
54
    case 'input':
55
      if (!(expression.name in inputs)) {
419✔
56
        throw new Error(`Unknown expression input '${expression.name}'`);
1✔
57
      }
58
      return;
418✔
59

60
    case 'literal':
61
      if (Array.isArray(expression.value)) {
94✔
62
        for (const value of expression.value) {
45✔
63
          if (!Number.isFinite(value)) {
132!
NEW
64
            throw new Error(
×
65
              `Expression literal array must contain only finite values, got ${value}`
66
            );
67
          }
68
        }
69
      } else if (!Number.isFinite(expression.value)) {
49!
NEW
70
        throw new Error(`Expression literal must be finite, got ${expression.value}`);
×
71
      }
72
      return;
94✔
73

74
    case 'call': {
75
      const operation = operations[expression.op];
293✔
76
      if (!operation) {
293!
NEW
77
        throw new Error(`Unknown expression op '${expression.op}'`);
×
78
      }
79
      if (expression.args.length !== operation.arity) {
293✔
80
        throw new Error(
1✔
81
          `Expression op '${expression.op}' expects ${operation.arity} args, got ${expression.args.length}`
82
        );
83
      }
84
      for (const argument of expression.args) {
292✔
85
        validateExpression(argument, {operations, inputs});
573✔
86
      }
87
      return;
292✔
88
    }
89

90
    default: {
NEW
91
      const unreachable: never = expression;
×
NEW
92
      throw new Error(`Unsupported expression node ${(unreachable as {kind?: string}).kind}`);
×
93
    }
94
  }
95
}
96

97
/**
98
 * Compiles an expression tree into a single inline scalar shader expression.
99
 *
100
 * The generated expression is side-effect free and intended for use in statements like
101
 * `result[i] = <expression>;`.
102
 */
103
export function compileExpression<OpT extends string>(
104
  expression: Expression<OpT>,
105
  options: CompileExpressionOptions<OpT>
106
): string {
107
  validateExpression(expression, options);
231✔
108
  return compileExpressionNode(expression, options);
231✔
109
}
110

111
function compileExpressionNode<OpT extends string>(
112
  expression: Expression<OpT>,
113
  options: CompileExpressionOptions<OpT>
114
): string {
115
  switch (expression.kind) {
804!
116
    case 'input': {
117
      const input = options.inputs[expression.name];
418✔
118
      if (options.laneIndex < input.size) {
418✔
119
        return options.formatInput(expression.name);
400✔
120
      }
121
      return options.formatOutOfBoundsInput(expression.name);
18✔
122
    }
123

124
    case 'literal':
125
      return options.formatLiteral(expression.value);
94✔
126

127
    case 'call': {
128
      const operation = options.operations[expression.op];
292✔
129
      const argumentsCode = expression.args.map(argument =>
292✔
130
        compileExpressionNode(argument, options)
573✔
131
      );
132
      return options.formatCall(operation.symbol, argumentsCode);
292✔
133
    }
134

135
    default: {
NEW
136
      const unreachable: never = expression;
×
NEW
137
      throw new Error(`Unsupported expression node ${(unreachable as {kind?: string}).kind}`);
×
138
    }
139
  }
140
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc