Skip to content

Commit bbe2fe7

Browse files
committed
feat(glsl): primitive array support
1 parent a582860 commit bbe2fe7

File tree

9 files changed

+160
-54
lines changed

9 files changed

+160
-54
lines changed

src/glsl/builtin.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import { swizzle } from './swizzle';
55
import { prepare, fastCalc } from './fast-calc';
6-
import { cls, typ, fun } from '../index';
6+
import { cls, typ, fun, checkType as check } from '../index';
77
import { readOnlyView, BLOCKED, isNumber } from '../utils';
88
import { Texture2D } from './builtin-texture';
99

@@ -19,7 +19,12 @@ function checkType(args, Type) {
1919
return readOnlyView(t);
2020
}
2121
const [first] = args;
22-
if (typeof first === 'function') {
22+
if (Array.isArray(first)) {
23+
return readOnlyView(first.map((el) => {
24+
check(el, Type);
25+
return el;
26+
}));
27+
} else if (typeof first === 'function') {
2328
return fun(Type, first);
2429
}
2530
}

src/glsl/index.js

Lines changed: 51 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,6 @@ function handleNode(node) {
9494
if (type === 'Property') {
9595
return prop(node);
9696
}
97-
// if (type === 'ArrayExpression') {
98-
// return arrExp(node);
99-
// }
10097
console.warn(`//handleNode() unkown type ${type}`, node);
10198
return `//handleNode() unkown type ${type}`;
10299
}
@@ -131,10 +128,6 @@ function conExp({ test, consequent, alternate }) {
131128
return `${handleNode(test)} ? ${handleNode(consequent)} : ${handleNode(alternate)}`;
132129
}
133130

134-
// function arrExp({ elements }) {
135-
// return `{${elements.map(handleNode).join(', ')}}`;
136-
// }
137-
138131
function ifStat(node) {
139132
const { alternate, consequent, test } = node;
140133
let alt = '';
@@ -296,53 +289,67 @@ function handleAssign(node) {
296289
if (init.type === 'ArrowFunctionExpression') {
297290
typeAnnotation = init.returnType;
298291
allocation = handleNode(init);
299-
} else if (init.type === 'CallExpression') {
300-
301-
switch (typeAnnotation) {
302-
case 'int':
303-
case 'float':
304-
case 'bool':
305-
case 'vec2':
306-
case 'vec3':
307-
case 'vec4':
308-
case 'mat3':
309-
case 'mat4':
310-
if (init.arguments.length) {
311-
allocation = ` = ${handleNode(init)}`;
312-
} else {
313-
allocation = '';
314-
}
315-
break;
316-
default:
317-
if (init.arguments.length) {
318-
if (init.arguments.length === 1) {
319-
allocation = ` = ${handleNode(init.arguments[0])}`;
292+
} else {
293+
allocation = handleAlloc(init, typeAnnotation);
294+
}
295+
}
296+
297+
let qualifier = '';
298+
if (q) {
299+
qualifier = `${q} `;
300+
}
301+
return `${qualifier}${typeAnnotation} ${name}${allocation}`;
302+
}
303+
304+
function handleAlloc(init, typeAnnotation) {
305+
let allocation = '';
306+
if (init.type === 'CallExpression') {
307+
308+
switch (typeAnnotation) {
309+
case 'int':
310+
case 'float':
311+
case 'bool':
312+
case 'vec2':
313+
case 'vec3':
314+
case 'vec4':
315+
case 'mat3':
316+
case 'mat4':
317+
if (init.arguments.length) {
318+
allocation = ` = ${handleNode(init)}`;
319+
} else {
320+
allocation = '';
321+
}
322+
break;
323+
default:
324+
if (init.arguments.length) {
325+
if (init.arguments.length === 1) {
326+
const [first] = init.arguments;
327+
if (first.type === 'ArrayExpression') {
328+
allocation = ` = ${typeAnnotation}(${first.elements.map(handleNode).join(', ')})`;
320329
} else {
321-
throwError(`classes dont support init calls yet ${typeAnnotation}`, init);
330+
allocation = ` = ${handleNode(init.arguments[0])}`;
322331
}
332+
} else {
333+
throwError(`classes dont support init calls yet ${typeAnnotation}`, init);
323334
}
324-
break;
325-
}
326-
} else if (init.type === 'NewExpression') {
327-
if (init.arguments.length) {
328-
if (init.arguments.length === 1) {
329-
allocation = ` = ${handleNode(init.arguments[0])}`;
330-
} else {
331-
throwError(`classes dont support init calls yet ${typeAnnotation}`, init);
332335
}
336+
break;
337+
}
338+
} else if (init.type === 'NewExpression') {
339+
if (init.arguments.length) {
340+
if (init.arguments.length === 1) {
341+
allocation = ` = ${handleNode(init.arguments[0])}`;
333342
} else {
334-
allocation = '';
343+
throwError(`classes dont support init calls yet ${typeAnnotation} `, init);
335344
}
336345
} else {
337-
allocation = ` = ${handleNode(init)}`;
346+
allocation = '';
338347
}
348+
} else {
349+
allocation = ` = ${handleNode(init)}`;
339350
}
340351

341-
let qualifier = '';
342-
if (q) {
343-
qualifier = `${q} `;
344-
}
345-
return `${qualifier}${typeAnnotation} ${name}${allocation}`;
352+
return allocation;
346353
}
347354

348355
function handleBody(body, tabCount = 0) {

src/index.d.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,9 @@ type TypedCls<T, Con extends Function> = { new(...args: Parameters<Con>): T };
3636

3737
export declare function typ<T>(type: (IsType<T>)): T;
3838

39-
40-
type Bind = CallableFunction['bind'];
41-
39+
// type Bind = CallableFunction['bind'];
4240

4341
export declare function fun<F extends Function>(func: SameType<ReturnType<F>, void, F>): { (...args: Parameters<F>): ReturnType<F> };
4442
export declare function fun<T, F extends Function>(type: IsType<T>, func: SameType<ReturnType<F>, T, F>): { (...args: Parameters<F>): ReturnType<F> };
4543

4644
export declare function cls<T extends Proto>(prototype: T): TypedCls<Omit<T, 'constructor'>, T['constructor']>;
47-

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ function extractType(type) {
152152
throw new Error(`no type found ${type}`);
153153
}
154154

155-
function checkType(value, expectedType, msg) {
155+
export function checkType(value, expectedType, msg) {
156156
value = getSource(value);
157157
expectedType = getSource(expectedType);
158158

src/jstree.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,17 @@ function extractType(node, target, options) {
6464
const [firstArg] = args;
6565
firstArg.returnType = callee.name;
6666
target.newInit = handleParams(firstArg, options);
67+
} else if (args[0] && (args[0].type === 'ArrayExpression')) {
68+
const [firstArg] = args;
69+
target.typeAnnotation = `${callee.name}[${firstArg.elements.length}]`;
70+
target.newInit = {
71+
...node, arguments: [handleNode(firstArg, options)]
72+
};
6773
} else {
74+
6875
const typeAnnotation = callee.name;
76+
77+
6978
target.typeAnnotation = typeAnnotation;
7079
target.newInit = node;
7180
}
@@ -84,6 +93,25 @@ function extractType(node, target, options) {
8493
target.typeAnnotation = string;
8594
}
8695
target.newInit = node;
96+
} else if (type === 'UnaryExpression') {
97+
const { argument, operator } = node;
98+
const { value, raw } = argument;
99+
if (typeof value === 'number') {
100+
if (raw.indexOf('.') < 0) {
101+
target.typeAnnotation = integer;
102+
} else {
103+
target.typeAnnotation = float;
104+
}
105+
} else if (typeof value === 'boolean') {
106+
target.typeAnnotation = boolean;
107+
} else {
108+
target.typeAnnotation = string;
109+
}
110+
target.newInit = {
111+
...argument,
112+
raw: `${operator}${raw}`,
113+
value: operator === '-' ? -value : value
114+
};
87115
} else if (type === 'ArrowFunctionExpression') {
88116
target.newInit = handleParams(node, options);
89117
target.newInit.returnType = 'void';
@@ -143,7 +171,7 @@ function handleNode(node, options) {
143171

144172
export function parse(input, { qualifiers = [], float = 'Number', integer = float, string = 'String', boolean = 'Boolean', locations = false, ranges = false, ...options } = {}) {
145173
// TODO: use onToken !!!!
146-
const ast = acorn.parse(input, { ...options, locations, ranges });
174+
const ast = acorn.parse(input, { ...options, locations, ranges, ecmaVersion: 6 });
147175
const node = handleNode(ast, { qualifiers, integer, float, string, boolean });
148176

149177
return node;

test/glsl/index.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,30 @@ MyType bar;
190190
assert.equal(glsl.trim(), expected.trim());
191191
});
192192

193+
it('works with float arrays', () => {
194+
const { glsl } = buildGLSL(() => {
195+
let foo = float([1.0, 2.0]);
196+
});
197+
198+
const expected = `
199+
float[2] foo = float[2](1.0, 2.0);
200+
`;
201+
202+
assert.equal(glsl.trim(), expected.trim());
203+
});
204+
205+
it('works with vec arrays', () => {
206+
const { glsl } = buildGLSL(() => {
207+
let foo = vec2([vec2(1.0, 2.0), vec(3.0, 4.0)]);
208+
});
209+
210+
const expected = `
211+
vec2[2] foo = vec2[2](vec2(1.0, 2.0), vec(3.0, 4.0));
212+
`;
213+
214+
assert.equal(glsl.trim(), expected.trim());
215+
});
216+
193217
it('works with joining chunks', () => {
194218
const one = buildGLSL(() => {
195219
let foo = uniform(vec2);

test/glsl/sim.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,20 @@ vec4 bar(vec2 x) {
456456
assert.equal(result.y, 0);
457457
});
458458

459+
it('works fine with primitive arrays', () => {
460+
const shader = ({ vec2 }) => {
461+
let bar = vec2([vec2(1.0, 2.0), vec2(3.0, 4.0)]);
462+
return { bar };
463+
};
464+
const { js } = buildGLSL(shader, { js: true, glsl: false });
465+
466+
const { bar: [v1, v2] } = js;
467+
assert.equal(v1.x, 1);
468+
assert.equal(v1.y, 2);
469+
assert.equal(v2.x, 3);
470+
assert.equal(v2.y, 4);
471+
});
472+
459473
it('throws an error when trying to change props of an argument.', () => {
460474
const shader = ({ fun, vec2 }) => {
461475
let bar = fun((x = vec2()) => {

test/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ class Test {
88
}
99

1010
describe('type tests', () => {
11-
12-
1311
// const f1 = (str = typ(string)) => {
1412
// return parseFloat(str);
1513
// }

test/jstree.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,25 @@ describe('jstree implicit tests', () => {
247247
assert.equal(id.qualifier, null);
248248
});
249249

250+
it('extract array type and init from implicit VariableDeclarator', () => {
251+
const node = parse(`
252+
let foo = String(['foo', 'bar']);
253+
`);
254+
255+
const [declarator] = node.body[0].declarations;
256+
const { id, init } = declarator;
257+
258+
assert.equal(init.type, 'CallExpression');
259+
assert.equal(init.callee.name, 'String');
260+
assert.equal(init.arguments[0].elements[0].value, 'foo');
261+
assert.equal(init.arguments[0].elements[1].value, 'bar');
262+
263+
assert.equal(id.type, 'Identifier');
264+
assert.equal(id.typeAnnotation, 'String[2]');
265+
assert.equal(id.name, 'foo');
266+
assert.equal(id.qualifier, null);
267+
});
268+
250269
it('extract type and init from implicit VariableDeclarator inside fun with multiple args', () => {
251270
const node = parse(`let x = Vec2(() => {
252271
let foo = Vec2(3.0, 2.0);
@@ -339,6 +358,20 @@ describe('jstree autodetect primitive tests', () => {
339358
assert.equal(init.raw, '5.0');
340359
});
341360

361+
it('extract type via autodetect unary float', () => {
362+
const node = parse('let x = +5.0;', { float: 'SPECIAL' });
363+
364+
const [declarator] = node.body[0].declarations;
365+
const { id, init } = declarator;
366+
367+
assert.equal(id.type, 'Identifier');
368+
assert.equal(id.typeAnnotation, 'SPECIAL');
369+
assert.equal(id.name, 'x');
370+
assert.equal(id.qualifier, null);
371+
assert.equal(init.raw, '+5.0');
372+
});
373+
374+
342375
it('extract type via autodetect integer', () => {
343376
const node = parse('let x = 5;', { integer: 'SPECIAL' });
344377

0 commit comments

Comments
 (0)