Skip to content

Commit 0d4351a

Browse files
Xiaoji Chendy
authored andcommitted
support in/out qualifiers
1 parent 2a55957 commit 0d4351a

File tree

2 files changed

+185
-8
lines changed

2 files changed

+185
-8
lines changed

lib/index.js

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,22 @@ GLSL.prototype.transforms = {
400400
return `${arg.type}`
401401
}).join('_')
402402

403+
//sort arguments by qualifier
404+
var inArgs = []
405+
var outArgs = []
406+
args.components.forEach(function (arg, index) {
407+
arg.index = index;
408+
if (arg.qualifier.slice(0, 2) === 'in') {
409+
inArgs.push(arg)
410+
}
411+
if (arg.qualifier.slice(-3) === 'out') {
412+
outArgs.push(arg)
413+
}
414+
})
415+
if (outArgs.length === 0) {
416+
outArgs = null;
417+
}
418+
403419
//if main name is registered - provide type-scoped name of function
404420
if (this.functions[name] && argTypesSfx) {
405421
name = `${name}_${argTypesSfx}`
@@ -410,7 +426,24 @@ GLSL.prototype.transforms = {
410426

411427
//create function body
412428
result += `function ${name} (${args}) {\n`
429+
430+
//input parameters are copied
431+
inArgs.forEach(function (arg) {
432+
if (/^(vec|mat)/.test(arg.type)) {
433+
result += `${arg} = ${arg}.slice();\n`
434+
}
435+
})
436+
437+
var scope = this.scopes[this.currentScope];
438+
scope.callName = name;
439+
scope.outArgs = outArgs;
440+
413441
result += this.process(node.children[2])
442+
443+
if (outArgs && outType === 'void') {
444+
result += `\n${name}.__out__ = [${outArgs.join(', ')}];`
445+
}
446+
414447
result = result.replace(/\n/g, '\n\t')
415448
result += '\n}'
416449

@@ -423,6 +456,8 @@ GLSL.prototype.transforms = {
423456
complexity: 999
424457
})
425458

459+
result.outArgs = outArgs;
460+
426461
//register function descriptor
427462
this.functions[name] = result
428463

@@ -480,6 +515,14 @@ GLSL.prototype.transforms = {
480515
//case of function args - drop var
481516
if (node.parent.type === 'functionargs') {
482517
result = this.process(decllist)
518+
519+
var qualifier = node.token.data
520+
if (qualifier === result.type) {
521+
result.qualifier = 'in'
522+
} else {
523+
result.qualifier = qualifier
524+
}
525+
483526
return result
484527
}
485528
//default type, like variable decl etc
@@ -723,7 +766,20 @@ GLSL.prototype.transforms = {
723766

724767
return: function (node) {
725768
var expr = this.process(node.children[0])
726-
return Descriptor('return' + (expr.visible ? ' ' + expr : ''), {type: expr.type})
769+
var result;
770+
var scope = this.scopes[this.currentScope];
771+
if (scope.outArgs) {
772+
var outStmt = `${scope.callName}.__out__ = [${scope.outArgs.join(', ')}]`
773+
774+
if (expr.visible) {
775+
result = `${scope.callName}.__return__ = ${expr};\n${outStmt};\nreturn ${scope.callName}.__return__`
776+
} else {
777+
result = `${outStmt};\nreturn`
778+
}
779+
} else {
780+
result = 'return' + (expr.visible ? ' ' + expr : '');
781+
}
782+
return Descriptor(result, {type: expr.type})
727783
},
728784

729785
continue: function () {return Descriptor('continue')},
@@ -1064,19 +1120,23 @@ GLSL.prototype.transforms = {
10641120

10651121
//someFn()
10661122
else {
1067-
var type, optimize = true
1123+
var type, optimize = true, outArgs = null
10681124

10691125
//registered fn()
1070-
if (this.functions[callName]) {
1126+
var fn = this.functions[callName]
1127+
if (fn) {
10711128
var sfx = argTypes.join('_')
10721129
if (sfx && this.functions[`${callName}_${sfx}`]) {
1073-
type = this.functions[`${callName}_${sfx}`].type
1130+
fn = this.functions[`${callName}_${sfx}`]
1131+
type = fn.type
1132+
outArgs = fn.outArgs
10741133
callName = Descriptor(`${callName}_${sfx}`, {
10751134
complexity: callName.complexity
10761135
})
10771136
}
1078-
else if (this.functions[callName]) {
1079-
type = this.functions[callName].type
1137+
else {
1138+
type = fn.type
1139+
outArgs = fn.outArgs
10801140
}
10811141
}
10821142

@@ -1104,15 +1164,23 @@ GLSL.prototype.transforms = {
11041164
type = null
11051165
optimize = false
11061166
}
1107-
var res = Descriptor(`${callName}(${argValues.join(', ')})`, {
1167+
1168+
var res = `${callName}(${argValues.join(', ')})`;
1169+
if (outArgs) {
1170+
var outList = outArgs.map(function (arg) {
1171+
return argValues[arg.index]
1172+
});
1173+
res = `(${res}, [${outList.join(', ')}] = ${callName}.__out__, ${callName}.__return__)`
1174+
}
1175+
1176+
return Descriptor(res, {
11081177
type: type || callName.type,
11091178
complexity: 999 /* argValues.reduce(function (prev, curr) {
11101179
return curr.complexity+prev
11111180
}, callName.complexity||999) */,
11121181
optimize: optimize
11131182
})
11141183

1115-
return res
11161184
}
11171185
}
11181186
},

test/index.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ test('Episodes', function () {
268268

269269
assert.equal(clean(compile(this.title)), clean(`
270270
function permute (x) {
271+
x = x.slice();
271272
return mod289([(x[0] * 34.0 + 1.0) * x[0], (x[1] * 34.0 + 1.0) * x[1], (x[2] * 34.0 + 1.0) * x[2]]);
272273
};
273274
`))
@@ -327,6 +328,114 @@ test('Episodes', function () {
327328
})
328329
});
329330

331+
test('Argument qualifiers', function() {
332+
333+
// clone inputs
334+
test('void f(float a, vec3 b, mat4 c) { b.x = 1.0; }', function () {
335+
var compile = GLSL();
336+
337+
assert.equal(clean(compile(this.title)), clean(`
338+
function f (a, b, c) {
339+
b = b.slice();
340+
c = c.slice();
341+
b[0] = 1.0;
342+
};
343+
`))
344+
});
345+
346+
// output w/o return statement
347+
test('void f(float a, out float b) { b = 1.0; }', function () {
348+
var compile = GLSL();
349+
350+
assert.equal(clean(compile(this.title)), clean(`
351+
function f (a, b) {
352+
b = 1.0;
353+
f.__out__ = [b];
354+
};
355+
`))
356+
});
357+
358+
// output w/ return statement
359+
test('void f(float a, out float b) { if (a < 0.0) { b = -1.0; return; } b = 1.0; }', function () {
360+
var compile = GLSL();
361+
362+
assert.equal(clean(compile(this.title)), clean(`
363+
function f (a, b) {
364+
if (a < 0.0) {
365+
b = -1.0;
366+
f.__out__ = [b];
367+
return;
368+
};
369+
b = 1.0;
370+
f.__out__ = [b];
371+
};
372+
`))
373+
});
374+
375+
// multiple outputs
376+
test('float f(out float a, out vec2 b, inout vec2 c) { a = 0.1; b = vec2(2.0); c = b; return 0.0; }', function () {
377+
var compile = GLSL();
378+
379+
assert.equal(clean(compile(this.title)), clean(`
380+
function f (a, b, c) {
381+
c = c.slice();
382+
a = 0.1;
383+
b = [2.0, 2.0];
384+
c = b;
385+
f.__return__ = 0.0;
386+
f.__out__ = [a, b, c];
387+
return f.__return__;
388+
};
389+
`))
390+
});
391+
392+
// calling
393+
test(`float f(float a, out float b, out float c) { b = 1.0; c = 2.0; return a + 1.0; }
394+
void main() { float x = 0.1; float y; float z; x = f(x, y, z); }`, function () {
395+
var compile = GLSL();
396+
assert.equal(clean(compile(this.title)), clean(`
397+
function f (a, b, c) {
398+
b = 1.0;
399+
c = 2.0;
400+
f.__return__ = a + 1.0;
401+
f.__out__ = [b, c];
402+
return f.__return__;
403+
};
404+
function main () {
405+
var x = 0.1;
406+
var y = 0;
407+
var z = 0;
408+
x = (f(x, y, z), [y, z] = f.__out__, f.__return__);
409+
};
410+
`))
411+
});
412+
413+
// recursive calling
414+
test(`float f1(float a, out float b) { b = 1.0; return a + 1.0; }
415+
float f2(float a, out float b) { return f1(a, b) + 1.0; }
416+
void main() { float x = 0.1; float y; x = f2(x, y); }`, function () {
417+
var compile = GLSL();
418+
assert.equal(clean(compile(this.title)), clean(`
419+
function f1 (a, b) {
420+
b = 1.0;
421+
f1.__return__ = a + 1.0;
422+
f1.__out__ = [b];
423+
return f1.__return__;
424+
};
425+
function f2 (a, b) {
426+
f2.__return__ = (f1(a, b), [b] = f1.__out__, f1.__return__) + 1.0;
427+
f2.__out__ = [b];
428+
return f2.__return__;
429+
};
430+
function main () {
431+
var x = 0.1;
432+
var y = 0;
433+
x = (f2(x, y), [y] = f2.__out__, f2.__return__);
434+
};
435+
`))
436+
});
437+
})
438+
330439

331440
test('Real cases', function () {
332441
//FIXME: make parser handle things properly

0 commit comments

Comments
 (0)