Skip to content

Commit 38f2c7a

Browse files
author
Aayushdev18
committed
Fix || and && operators in p5.strands if conditions
Add LogicalExpression handler to transpile logical operators to .or() and .and() method calls. Fixes #8358.
1 parent 7fa997e commit 38f2c7a

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

src/strands/strands_transpiler.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,37 @@ const ASTCallbacks = {
275275
};
276276
node.arguments = [node.right];
277277
},
278+
LogicalExpression(node, _state, ancestors) {
279+
// Don't convert uniform default values to node methods, as
280+
// they should be evaluated at runtime, not compiled.
281+
if (ancestors.some(nodeIsUniform)) { return; }
282+
// If the left hand side of an expression is one of these types,
283+
// we should construct a node from it.
284+
const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier'];
285+
if (unsafeTypes.includes(node.left.type)) {
286+
const leftReplacementNode = {
287+
type: 'CallExpression',
288+
callee: {
289+
type: 'Identifier',
290+
name: '__p5.strandsNode',
291+
},
292+
arguments: [node.left]
293+
}
294+
node.left = leftReplacementNode;
295+
}
296+
// Replace the logical operator with a call expression
297+
// in other words a call to BaseNode.or(), .and() etc.
298+
node.type = 'CallExpression';
299+
node.callee = {
300+
type: 'MemberExpression',
301+
object: node.left,
302+
property: {
303+
type: 'Identifier',
304+
name: replaceBinaryOperator(node.operator),
305+
},
306+
};
307+
node.arguments = [node.right];
308+
},
278309
IfStatement(node, _state, ancestors) {
279310
if (ancestors.some(nodeIsUniform)) { return; }
280311
// Transform if statement into strandsIf() call

test/unit/webgl/p5.Shader.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,52 @@ suite('p5.Shader', function() {
714714
assert.approximately(pixelColor[1], 255, 5); // Green channel should be 255
715715
assert.approximately(pixelColor[2], 255, 5); // Blue channel should be 255
716716
});
717+
test('handle if statement with || (OR) operator', () => {
718+
myp5.createCanvas(50, 50, myp5.WEBGL);
719+
const testShader = myp5.baseMaterialShader().modify(() => {
720+
myp5.getPixelInputs(inputs => {
721+
let c = [1, 1, 1, 1];
722+
if (myp5.abs(inputs.texCoord.x - 0.5) > 0.2 || myp5.abs(inputs.texCoord.y - 0.5) > 0.2) {
723+
c = [1, 0, 0, 1];
724+
}
725+
inputs.color = c;
726+
return inputs;
727+
});
728+
}, { myp5 });
729+
myp5.noStroke();
730+
myp5.shader(testShader);
731+
myp5.plane(myp5.width, myp5.height);
732+
const centerPixel = myp5.get(25, 25);
733+
assert.approximately(centerPixel[0], 255, 5);
734+
assert.approximately(centerPixel[1], 255, 5);
735+
assert.approximately(centerPixel[2], 255, 5);
736+
const edgePixel = myp5.get(5, 25);
737+
assert.approximately(edgePixel[0], 255, 5);
738+
assert.approximately(edgePixel[1], 0, 5);
739+
assert.approximately(edgePixel[2], 0, 5);
740+
});
741+
test('handle if statement with && (AND) operator', () => {
742+
myp5.createCanvas(50, 50, myp5.WEBGL);
743+
const testShader = myp5.baseMaterialShader().modify(() => {
744+
const condition1 = myp5.uniformFloat(() => 1.0);
745+
const condition2 = myp5.uniformFloat(() => 1.0);
746+
myp5.getPixelInputs(inputs => {
747+
let color = myp5.float(0.0);
748+
if (condition1 > 0.5 && condition2 > 0.5) {
749+
color = myp5.float(1.0);
750+
}
751+
inputs.color = [color, color, color, 1.0];
752+
return inputs;
753+
});
754+
}, { myp5 });
755+
myp5.noStroke();
756+
myp5.shader(testShader);
757+
myp5.plane(myp5.width, myp5.height);
758+
const pixelColor = myp5.get(25, 25);
759+
assert.approximately(pixelColor[0], 255, 5);
760+
assert.approximately(pixelColor[1], 255, 5);
761+
assert.approximately(pixelColor[2], 255, 5);
762+
});
717763
// Keep one direct API test for completeness
718764
test('handle direct StrandsIf API usage', () => {
719765
myp5.createCanvas(50, 50, myp5.WEBGL);

0 commit comments

Comments
 (0)