From b0b93d030387b72d595c6ec2d86f1a1b20a65b57 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sat, 16 Dec 2017 16:05:02 -0500 Subject: [PATCH 1/4] Add ASTfieldselect base class in preparation for color/vector rgb selectors. --- src/liboslcomp/ast.cpp | 29 ++++++++++++++++++---------- src/liboslcomp/ast.h | 29 ++++++++++++++++++++++------ src/liboslcomp/oslgram.y | 2 +- testsuite/oslc-err-field/ref/out.txt | 7 +++++-- testsuite/oslc-err-field/test.osl | 8 ++++++++ 5 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/liboslcomp/ast.cpp b/src/liboslcomp/ast.cpp index 4bf8195f7..1c6f5974d 100644 --- a/src/liboslcomp/ast.cpp +++ b/src/liboslcomp/ast.cpp @@ -694,12 +694,12 @@ ASTindex::childname (size_t i) const ASTstructselect::ASTstructselect (OSLCompilerImpl *comp, ASTNode *expr, ustring field) - : ASTNode (structselect_node, comp, 0, expr), m_field(field), + : ASTfieldselect (structselect_node, comp, expr, field), m_structid(-1), m_fieldid(-1), m_fieldsym(NULL) { m_fieldsym = find_fieldsym (m_structid, m_fieldid); if (m_fieldsym) { - m_fieldname = m_fieldsym->name(); + m_fullname = m_fieldsym->name(); m_typespec = m_fieldsym->typespec(); } } @@ -712,12 +712,7 @@ ASTstructselect::ASTstructselect (OSLCompilerImpl *comp, ASTNode *expr, Symbol * ASTstructselect::find_fieldsym (int &structid, int &fieldid) { - if (! lvalue()->typespec().is_structure() && - ! lvalue()->typespec().is_structure_array()) { - error ("type '%s' does not have a member '%s'", - type_c_str(lvalue()->typespec()), m_field); - return NULL; - } + ASSERT (lvalue()->typespec().is_structure_based()); ustring structsymname; TypeSpec structtype; @@ -763,8 +758,7 @@ ASTstructselect::find_structsym (ASTNode *structnode, ustring &structname, // or array of structs) down to a symbol that represents the // particular field. In the process, we set structname and its // type structtype. - ASSERT (structnode->typespec().is_structure() || - structnode->typespec().is_structure_array()); + ASSERT (structnode->typespec().is_structure_based()); if (structnode->nodetype() == variable_ref_node) { // The structnode is a top-level struct variable ASTvariable_ref *var = (ASTvariable_ref *) structnode; @@ -811,6 +805,21 @@ ASTstructselect::print (std::ostream &out, int indentlevel) const +ASTfieldselect* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, + ustring field) { + if (expr->typespec().is_structure_based()) + return new ASTstructselect (comp, expr, field); + + comp->error (comp->filename(), comp->lineno(), + "type '%s' does not have a member '%s'", + comp->type_c_str(expr->typespec()), field); + + // Don't leak expr node + delete expr; + return nullptr; +} + + const char * ASTconditional_statement::childname (size_t i) const { diff --git a/src/liboslcomp/ast.h b/src/liboslcomp/ast.h index de6965771..45d14c4f3 100644 --- a/src/liboslcomp/ast.h +++ b/src/liboslcomp/ast.h @@ -588,7 +588,28 @@ class ASTindex : public ASTNode -class ASTstructselect : public ASTNode +class ASTfieldselect : public ASTNode +{ +protected: + ASTfieldselect (NodeType type, OSLCompilerImpl *comp, ASTNode *expr, + ustring field) : + ASTNode(type, comp, Nothing, expr), m_field(field) {} + + ustring m_field; ///< Name of the field + ustring m_fullname; ///< Full name of variable and field + +public: + static ASTfieldselect* create (OSLCompilerImpl *comp, ASTNode *expr, + ustring field); + + ustring field () const { return m_field; } + ustring fullname () const { return m_fullname; } + ref lvalue () const { return child (0); } +}; + + + +class ASTstructselect : public ASTfieldselect { public: ASTstructselect (OSLCompilerImpl *comp, ASTNode *expr, ustring field); @@ -602,9 +623,7 @@ class ASTstructselect : public ASTNode /// field. void codegen_assign (Symbol *dest, Symbol *src); - ref lvalue () const { return child (0); } - ustring field () const { return m_field; } - ustring fieldname () const { return m_fieldname; } + ustring fieldname () const { return fullname(); } Symbol *fieldsym () const { return m_fieldsym; } private: @@ -613,10 +632,8 @@ class ASTstructselect : public ASTNode TypeSpec &structtype); Symbol *codegen_index (); - ustring m_field; ///< Name of the field int m_structid; ///< index of the structure int m_fieldid; ///< index of the field within the structure - ustring m_fieldname; ///< Name of the field variable Symbol *m_fieldsym; ///< Symbol of the field variable }; diff --git a/src/liboslcomp/oslgram.y b/src/liboslcomp/oslgram.y index af4842b96..0bca41f6a 100644 --- a/src/liboslcomp/oslgram.y +++ b/src/liboslcomp/oslgram.y @@ -780,7 +780,7 @@ id_or_field } | variable_lvalue '.' IDENTIFIER { - $$ = new ASTstructselect (oslcompiler, $1, ustring($3)); + $$ = ASTfieldselect::create (oslcompiler, $1, ustring($3)); } ; diff --git a/testsuite/oslc-err-field/ref/out.txt b/testsuite/oslc-err-field/ref/out.txt index 617663258..260f3883c 100644 --- a/testsuite/oslc-err-field/ref/out.txt +++ b/testsuite/oslc-err-field/ref/out.txt @@ -1,3 +1,6 @@ -test.osl:8: error: type 'color' does not have a member 'nope' -test.osl:11: error: struct type 'custom' does not have a member 'bad' +test.osl:11: error: type 'color' does not have a member 'invalid' +test.osl:12: error: type 'color' does not have a member 'nope' +test.osl:15: error: struct type 'custom' does not have a member 'bad' +test.osl:18: error: type 'color' does not have a member 'sinvalid' +test.osl:19: error: type 'color' does not have a member 'error' FAILED test.osl diff --git a/testsuite/oslc-err-field/test.osl b/testsuite/oslc-err-field/test.osl index cad6fec5e..ce0f21154 100644 --- a/testsuite/oslc-err-field/test.osl +++ b/testsuite/oslc-err-field/test.osl @@ -1,12 +1,20 @@ // Test invalid field selections in function calls struct custom { float field; }; +struct A { color valid; }; +struct B { A a; }; +struct C { B b; }; shader test () { color c = color(4,3,2); + c.invalid = 45; printf("c.nope: %g\n", c.nope); custom cc = { 1 }; printf("cc.bad: %g\n", cc.bad); + + C nested; + nested.b.a.valid.sinvalid = color(1); + printf("nested.b.a.valid.error: %g\n", nested.b.a.valid.error); } From 03f8ee7d74541f27dfb232ed8e94aba7963868fa Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sat, 16 Dec 2017 20:17:20 -0500 Subject: [PATCH 2/4] Add r,g,b and x,y,z accessors to triple types. --- CMakeLists.txt | 1 + src/liboslcomp/ast.cpp | 30 ++++++++++++++++++++++++++++-- src/liboslcomp/ast.h | 10 ++++++++-- testsuite/swizzle/ref/out.txt | 15 +++++++++++++++ testsuite/swizzle/run.py | 4 ++++ testsuite/swizzle/swizzle.osl | 29 +++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 testsuite/swizzle/ref/out.txt create mode 100755 testsuite/swizzle/run.py create mode 100644 testsuite/swizzle/swizzle.osl diff --git a/CMakeLists.txt b/CMakeLists.txt index 5555b42df..9acf8fe5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -296,6 +296,7 @@ TESTSUITE ( aastep allowconnect-err and-or-not-synonyms arithmetic struct-isomorphic-overload struct-layers struct-operator-overload struct-return struct-with-array struct-nested struct-nested-assign struct-nested-deep + swizzle ternary testshade-expr texture-alpha texture-blur texture-connected-options diff --git a/src/liboslcomp/ast.cpp b/src/liboslcomp/ast.cpp index 1c6f5974d..dcdbc5a18 100644 --- a/src/liboslcomp/ast.cpp +++ b/src/liboslcomp/ast.cpp @@ -805,11 +805,37 @@ ASTstructselect::print (std::ostream &out, int indentlevel) const -ASTfieldselect* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, - ustring field) { +ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, + ustring field) +{ if (expr->typespec().is_structure_based()) return new ASTstructselect (comp, expr, field); + const TypeSpec &type = expr->nodetype() != structselect_node ? expr->typespec() : + static_cast(expr)->fieldsym()->typespec(); + + if (type.aggregate() == TypeDesc::VEC3) { + int component = -1; + switch (field[0]) { + case 'r': component = 0; break; + case 'g': component = 1; break; + case 'b': component = 2; break; + + case 'x': component = 0; break; + case 'y': component = 1; break; + case 'z': component = 2; break; + + default: break; + } + if (component != -1) { + if (expr->nodetype() == index_node) { + static_cast(expr)->extend(new ASTliteral (comp, component)); + return expr; + } + return new ASTindex (comp, expr, new ASTliteral (comp, component)); + } + } + comp->error (comp->filename(), comp->lineno(), "type '%s' does not have a member '%s'", comp->type_c_str(expr->typespec()), field); diff --git a/src/liboslcomp/ast.h b/src/liboslcomp/ast.h index 45d14c4f3..029fe5bc0 100644 --- a/src/liboslcomp/ast.h +++ b/src/liboslcomp/ast.h @@ -580,6 +580,13 @@ class ASTindex : public ASTNode ustring destname, ustring srcname, Symbol *index); + /// Add another index: obj[current][extended] + /// + void extend (ASTNode *ext) { + ASSERT (nchildren() < 4); + m_children.emplace_back(ext); + } + ref lvalue () const { return child (0); } ref index () const { return child (1); } ref index2 () const { return child (2); } @@ -599,8 +606,7 @@ class ASTfieldselect : public ASTNode ustring m_fullname; ///< Full name of variable and field public: - static ASTfieldselect* create (OSLCompilerImpl *comp, ASTNode *expr, - ustring field); + static ASTNode* create (OSLCompilerImpl *comp, ASTNode *expr, ustring field); ustring field () const { return m_field; } ustring fullname () const { return m_fullname; } diff --git a/testsuite/swizzle/ref/out.txt b/testsuite/swizzle/ref/out.txt new file mode 100644 index 000000000..c10a4d6b6 --- /dev/null +++ b/testsuite/swizzle/ref/out.txt @@ -0,0 +1,15 @@ +Compiled swizzle.osl -> swizzle.oso +c.r: 4 +c.g: 3 +c.b: 2 +v0.x: 6 +v0.y: 7 +v0.z: 8 +v0.z->x: 6 +c4[0].r: 1 +c4[0].g: 2 +c4[0].b: 3 +c4[1].r: -1 +c4[1].b: -3 +c4[1].g: -2 + diff --git a/testsuite/swizzle/run.py b/testsuite/swizzle/run.py new file mode 100755 index 000000000..f61ba00ef --- /dev/null +++ b/testsuite/swizzle/run.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +command = testshade("swizzle") + diff --git a/testsuite/swizzle/swizzle.osl b/testsuite/swizzle/swizzle.osl new file mode 100644 index 000000000..400a9dd43 --- /dev/null +++ b/testsuite/swizzle/swizzle.osl @@ -0,0 +1,29 @@ +// Test swizzle statements + +#include "color4.h" + +shader swizzle () +{ + color c = color(4,3,2); + printf("c.r: %g\n", c.r); + printf("c.g: %g\n", c.g); + printf("c.b: %g\n", c.b); + + vector v0 = vector(6,7,8); + printf("v0.x: %g\n", v0.x); + printf("v0.y: %g\n", v0.y); + printf("v0.z: %g\n", v0.z); + v0.z = v0.x; + printf("v0.z->x: %g\n", v0.r); + + color ca[2] = { color(-1,2,3), color(1,-2,-3) }; + color4 c4[2]; // FIXME: = { color4(color(1,2,3),4), color4(color(-1,-2,-3),-4) }; + + for (int i = 0; i < 2; ++i) { + ca[i].r = -ca[i].r; + c4[i].rgb = color(ca[i].x, ca[i].y, ca[i].z); + printf("c4[%d].r: %g\n", i, c4[i].rgb.r); + printf("c4[%d].%s: %g\n", i, i ? "b" : "g", i ? c4[i].rgb.b : c4[i].rgb.g); + printf("c4[%d].%s: %g\n", i, i ? "g" : "b", i ? c4[i].rgb.g : c4[i].rgb.b); + } +} From 71a38a85ef41cfa59b21ba126a1a8fbb62ee0fe9 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sat, 16 Dec 2017 21:10:39 -0500 Subject: [PATCH 3/4] Add support for swizzling triple types. --- src/liboslcomp/ast.cpp | 121 +++++++++++++++++++++++++++++----- src/liboslcomp/ast.h | 30 ++++++++- src/liboslcomp/codegen.cpp | 74 +++++++++++++++++++++ src/liboslcomp/typecheck.cpp | 16 +++++ testsuite/swizzle/ref/out.txt | 25 +++++++ testsuite/swizzle/swizzle.osl | 54 ++++++++++++++- 6 files changed, 302 insertions(+), 18 deletions(-) diff --git a/src/liboslcomp/ast.cpp b/src/liboslcomp/ast.cpp index dcdbc5a18..ccf3862d4 100644 --- a/src/liboslcomp/ast.cpp +++ b/src/liboslcomp/ast.cpp @@ -805,6 +805,65 @@ ASTstructselect::print (std::ostream &out, int indentlevel) const +ASTswizzle::ASTswizzle (OSLCompilerImpl *comp, ASTNode *expr, ustring field) : +ASTfieldselect(swizzle_node, comp, expr, field) +{ + if (field.size() == 1) m_typespec = TypeDesc::TypeFloat; + else m_typespec = TypeDesc::TypeVector; +} + + + +size_t ASTswizzle::indices (ustring components, int *indexes, size_t N, bool consts) +{ + size_t i = 0; + do { + switch (components[i]) { + case 'r': + case 'x': indexes[i] = 0; break; + case 'g': + case 'y': indexes[i] = 1; break; + case 'b': + case 'z': indexes[i] = 2; break; + + case '0': + if (!consts) + return 0; + indexes[i] = const_offset; + break; + case '1': + if (!consts) + return 0; + indexes[i] = const_offset + 1; + break; + + case '\0': return i; + + default: return 0; + } + } while (++i < N); + + return i; +} + + + +const char * +ASTswizzle::childname (size_t i) const +{ + return type_c_str(m_typespec); +} + + +void +ASTswizzle::print (std::ostream &out, int indentlevel) const +{ + ASTNode::print (out, indentlevel); + indent (out, indentlevel+1); + out << "components " << field() << "\n"; +} + + ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, ustring field) { @@ -814,25 +873,55 @@ ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, const TypeSpec &type = expr->nodetype() != structselect_node ? expr->typespec() : static_cast(expr)->fieldsym()->typespec(); - if (type.aggregate() == TypeDesc::VEC3) { - int component = -1; - switch (field[0]) { - case 'r': component = 0; break; - case 'g': component = 1; break; - case 'b': component = 2; break; + if (type.aggregate() == TypeDesc::VEC3 && field.size() <= 3) { + // Early out swizle to native component ordering. + if (field == "rgb" || field == "xyz") + return expr; - case 'x': component = 0; break; - case 'y': component = 1; break; - case 'z': component = 2; break; + ASTindex* index = expr->nodetype() != index_node ? nullptr : static_cast(expr); - default: break; - } - if (component != -1) { - if (expr->nodetype() == index_node) { - static_cast(expr)->extend(new ASTliteral (comp, component)); - return expr; + int indexes[3]; + switch (ASTswizzle::indices (field, indexes, 3, true)) { + case 1: { + if (!index) + return new ASTindex (comp, expr, new ASTliteral (comp, indexes[0])); + index->extend(new ASTliteral (comp, indexes[0])); + return index; + } + + case 3: { + // Don't leak soon to be unused expr node + std::unique_ptr cleanup(index); + ASTNode* index0 = nullptr; + if (index) { + index0 = index->index().get(); + expr = index->lvalue().get(); + } + + ASTNode *args[3]; + for (int i = 0; i < 3; ++i) { + if (indexes[i] >= 0) { + args[i] = new ASTliteral (comp, indexes[i]); + if (i == 0 && index) { + // Re-use expr by extending the ASTindex. + index->extend (args[i]); + args[0] = cleanup.release (); + } else { + args[i] = !index0 ? new ASTindex (comp, expr, args[i]) : + new ASTindex (comp, expr, index0, args[i]); + } + } else { + float cval = indexes[i] - ASTswizzle::const_offset; + ASSERT ((cval==0) || (cval==1)); + args[i] = new ASTliteral (comp, cval); + } + } + args[0]->append (args[1]); + args[1]->append (args[2]); + return new ASTswizzle (comp, args[0], field); } - return new ASTindex (comp, expr, new ASTliteral (comp, component)); + + default: break; } } diff --git a/src/liboslcomp/ast.h b/src/liboslcomp/ast.h index 029fe5bc0..138b7055a 100644 --- a/src/liboslcomp/ast.h +++ b/src/liboslcomp/ast.h @@ -62,7 +62,7 @@ class ASTNode : public OIIO::RefCnt { unknown_node, shader_declaration_node, function_declaration_node, variable_declaration_node, compound_initializer_node, variable_ref_node, preincdec_node, postincdec_node, - index_node, structselect_node, + index_node, structselect_node, swizzle_node, conditional_statement_node, loop_statement_node, loopmod_statement_node, return_statement_node, binary_expression_node, unary_expression_node, @@ -645,6 +645,34 @@ class ASTstructselect : public ASTfieldselect +class ASTswizzle : public ASTfieldselect +{ +public: + ASTswizzle (OSLCompilerImpl *comp, ASTNode *expr, ustring field); + + const char *nodetypename () const { return "swizzle"; } + const char *childname (size_t i) const; + void print (std::ostream &out, int indentlevel=0) const; + TypeSpec typecheck (TypeSpec expected); + Symbol *codegen (Symbol *dest = NULL); + + /// Get component indeces for a swizzle string. + /// consts allows '0' & '1' to be included in the string. + static size_t indices (ustring components, int *indexes, size_t N, bool consts); + + /// Offset if the component index is really a constant ('0' or '1'). + enum { const_offset = -2 }; + + /// Special code generation of assignment of src to proper components. + Symbol* codegen_assign (Symbol *src); + + size_t indices (int *indexes, size_t N, bool consts) const { + return indices (m_field, indexes, N, consts); + } +}; + + + class ASTconditional_statement : public ASTNode { public: diff --git a/src/liboslcomp/codegen.cpp b/src/liboslcomp/codegen.cpp index 39968d293..effaddc6a 100644 --- a/src/liboslcomp/codegen.cpp +++ b/src/liboslcomp/codegen.cpp @@ -488,6 +488,8 @@ ASTassign_expression::codegen (Symbol *dest) // Assigning to an individual component or array element index = (ASTindex *) var().get(); dest = NULL; + } else if (var()->nodetype() == swizzle_node) { + return static_cast(var().get())->codegen_assign(expr()->codegen (dest)); } else if (var()->nodetype() == structselect_node) { dest = var()->codegen(); } else { @@ -1294,6 +1296,78 @@ ASTindex::codegen_assign (Symbol *src, Symbol *ind, +Symbol * +ASTswizzle::codegen (Symbol *dest) +{ + // General case, construct a new triple with the swizzle indexes. + + if (dest == nullptr || ! equivalent (dest->typespec(), typespec())) + dest = m_compiler->make_temporary (typespec()); + + Symbol *syms[4] = { dest }; + + int nsym = 1; + for (ref arg = child(0); arg && nsym < 4; ++nsym, arg = arg->next()) { + syms[nsym] = arg->codegen(); + } + ASSERT (nsym == 4); + + // emit the constructor call + emitcode (typespec().string().c_str(), nsym, syms); + return dest; +} + + + +Symbol * +ASTswizzle::codegen_assign (Symbol *src) +{ + // Swizzle assignment. + + if (!m_is_lvalue) { + error ("Cannot assign to constant swizzle"); + return nullptr; + } + + // First child is an index, which holds the lvalue (this) to store to. + ASTindex* index = static_cast(child(0)); + Symbol *syms[4] = { index->lvalue().get()->codegen() }; + + int nsym = 0; + if (src->typespec().is_triple()) { + int idxs[3]; + if (indices(idxs, 3, false /*can't assign to constants*/) != 3) { + error ("Trying to assign to invalid swizzle"); + return nullptr; + } + // Iterate all of the indexes + for (; index && nsym < 3; ++nsym, index = static_cast(index->nextptr())) { + // tmp[I] = src[N] + ASSERT (index->nodetype() == index_node); + Symbol* sym = m_compiler->make_temporary (TypeDesc::TypeFloat); + emitcode ("compref", sym, src, m_compiler->make_constant (nsym)); + + // sym[0] is taken, so assign to syms[i+1] + ASSERT (idxs[nsym]+1 < int(sizeof(syms)/sizeof(syms[0]))); + syms[idxs[nsym]+1] = sym; + } + } else { + // Same assignment to all components + for (int n = m_typespec.aggregate(); nsym < n; ++nsym) + syms[nsym] = src; + } + + ASSERT (nsym == 3); + + // emit the constructor call + emitcode (typespec().string().c_str(), nsym+1, syms); + + // so transitive assignment will work + return syms[0]; +} + + + Symbol * ASTstructselect::codegen (Symbol *dest) { diff --git a/src/liboslcomp/typecheck.cpp b/src/liboslcomp/typecheck.cpp index 21419e4e1..98fd262fc 100644 --- a/src/liboslcomp/typecheck.cpp +++ b/src/liboslcomp/typecheck.cpp @@ -225,6 +225,22 @@ ASTindex::typecheck (TypeSpec expected) +TypeSpec +ASTswizzle::typecheck (TypeSpec expected) +{ + typecheck_children (); + + // Can't be an lvalue if any of the args are constant floats. + for (ref arg = child(0); arg; arg = arg->next()) { + if (!(m_is_lvalue = arg->is_lvalue())) + break; + } + + return m_typespec; +} + + + TypeSpec ASTstructselect::typecheck (TypeSpec expected) { diff --git a/testsuite/swizzle/ref/out.txt b/testsuite/swizzle/ref/out.txt index c10a4d6b6..cf493365e 100644 --- a/testsuite/swizzle/ref/out.txt +++ b/testsuite/swizzle/ref/out.txt @@ -1,4 +1,18 @@ Compiled swizzle.osl -> swizzle.oso +c: 1 2 3 +c.brg = c.grb = c.bgr: 3 1 2 +c.rgb = c.gbr: 1 2 3 +c.r00: 1 0 0 +c.g01: 2 0 1 +c.b11: 3 1 1 +c.bg1: 3 2 1 +c.rgb = c.brg: 3 1 2 +c.rgb = c.brg: 2 3 1 +c.rgb = c.brg: 1 2 3 +c.rgb = c.bgr: 3 2 1 +c.bgr = c.bgr: 3 2 1 +c.grb = c.bgr: 2 1 3 +c.ggr + c.rgr: 3 2 4 c.r: 4 c.g: 3 c.b: 2 @@ -12,4 +26,15 @@ c4[0].b: 3 c4[1].r: -1 c4[1].b: -3 c4[1].g: -2 +c.rrr: 4 4 4 +c.rgb: 4 3 2 +c.rbg: 4 2 3 +c.ggg: 3 3 3 +c.grb: 3 4 2 +c.gbr: 3 2 4 +c.bbb: 2 2 2 +c.brg: 2 4 3 +c.ggr: 3 3 4 +ca[0].brg: 3 1 2 +c.rgb = 1: 1 1 1 diff --git a/testsuite/swizzle/swizzle.osl b/testsuite/swizzle/swizzle.osl index 400a9dd43..65872e64d 100644 --- a/testsuite/swizzle/swizzle.osl +++ b/testsuite/swizzle/swizzle.osl @@ -4,7 +4,44 @@ shader swizzle () { - color c = color(4,3,2); + color c = color(1,2,3); + printf("c: %g\n", c); + + // transitive + // 1,2,3 -> 2,3,1 -> 3,1,2 + c.brg = c.grb = c.bgr; + printf("c.brg = c.grb = c.bgr: %g\n", c); + + c.rgb = c.gbr; + printf("c.rgb = c.gbr: %g\n", c); + + printf("c.r00: %g\n", c.r00); + printf("c.g01: %g\n", c.g01); + printf("c.b11: %g\n", c.b11); + printf("c.bg1: %g\n", c.bg1); + + c = c.brg; + printf("c.rgb = c.brg: %g\n", c); + + c = c.brg; + printf("c.rgb = c.brg: %g\n", c); + + c = c.brg; + printf("c.rgb = c.brg: %g\n", c); + + c.rgb = c.bgr; + printf("c.rgb = c.bgr: %g\n", c); + + c.bgr = c.bgr; + printf("c.bgr = c.bgr: %g\n", c); + + c.grb = c.bgr; + printf("c.grb = c.bgr: %g\n", c); + + printf("c.ggr + c.rgr: %g\n", c.ggr + c.rgr); + + c.gbr = c.ggr + c.rgr; + printf("c.r: %g\n", c.r); printf("c.g: %g\n", c.g); printf("c.b: %g\n", c.b); @@ -26,4 +63,19 @@ shader swizzle () printf("c4[%d].%s: %g\n", i, i ? "b" : "g", i ? c4[i].rgb.b : c4[i].rgb.g); printf("c4[%d].%s: %g\n", i, i ? "g" : "b", i ? c4[i].rgb.g : c4[i].rgb.b); } + + printf("c.rrr: %g\n", c.rrr); + printf("c.rgb: %g\n", c.rgb); + printf("c.rbg: %g\n", c.rbg); + printf("c.ggg: %g\n", c.ggg); + printf("c.grb: %g\n", c.grb); + printf("c.gbr: %g\n", c.gbr); + printf("c.bbb: %g\n", c.bbb); + printf("c.brg: %g\n", c.brg); + printf("c.ggr: %g\n", c.ggr); + + printf("ca[0].brg: %g\n", ca[0].brg); + + c.rgb = 1; + printf("c.rgb = 1: %g\n", c); } From f2e514e2e5d0b767351a9becea4c6ecea134c019 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sun, 17 Dec 2017 15:10:04 -0500 Subject: [PATCH 4/4] Allow swizzles to begin with a constant value. --- CMakeLists.txt | 1 + src/liboslcomp/ast.cpp | 16 ++++++++++++++-- src/liboslcomp/ast.h | 3 ++- src/liboslcomp/oslgram.y | 6 +++++- src/liboslcomp/osllex.l | 10 ++++++++++ testsuite/oslc-err-swizzle/ref/out.txt | 3 +++ testsuite/oslc-err-swizzle/run.py | 5 +++++ testsuite/oslc-err-swizzle/test.osl | 10 ++++++++++ testsuite/swizzle/ref/out.txt | 2 ++ testsuite/swizzle/swizzle.osl | 6 ++++++ 10 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 testsuite/oslc-err-swizzle/ref/out.txt create mode 100755 testsuite/oslc-err-swizzle/run.py create mode 100644 testsuite/oslc-err-swizzle/test.osl diff --git a/CMakeLists.txt b/CMakeLists.txt index 9acf8fe5f..c7eb3abf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -276,6 +276,7 @@ TESTSUITE ( aastep allowconnect-err and-or-not-synonyms arithmetic oslc-err-outputparamvararray oslc-err-paramdefault oslc-err-struct-array-init oslc-err-struct-ctr oslc-err-struct-dup oslc-err-struct-print + oslc-err-swizzle oslc-warn-commainit oslc-variadic-macro oslc-version diff --git a/src/liboslcomp/ast.cpp b/src/liboslcomp/ast.cpp index ccf3862d4..497d17a63 100644 --- a/src/liboslcomp/ast.cpp +++ b/src/liboslcomp/ast.cpp @@ -865,9 +865,9 @@ ASTswizzle::print (std::ostream &out, int indentlevel) const ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, - ustring field) + ustring field, bool swizzle) { - if (expr->typespec().is_structure_based()) + if (!swizzle && expr->typespec().is_structure_based()) return new ASTstructselect (comp, expr, field); const TypeSpec &type = expr->nodetype() != structselect_node ? expr->typespec() : @@ -883,6 +883,8 @@ ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, int indexes[3]; switch (ASTswizzle::indices (field, indexes, 3, true)) { case 1: { + // c.0 && c.1 not allowed + ASSERT (indexes[0] >= 0); if (!index) return new ASTindex (comp, expr, new ASTliteral (comp, indexes[0])); index->extend(new ASTliteral (comp, indexes[0])); @@ -890,6 +892,7 @@ ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, } case 3: { + bool allconst = true; // Don't leak soon to be unused expr node std::unique_ptr cleanup(index); ASTNode* index0 = nullptr; @@ -901,6 +904,7 @@ ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, ASTNode *args[3]; for (int i = 0; i < 3; ++i) { if (indexes[i] >= 0) { + allconst = false; args[i] = new ASTliteral (comp, indexes[i]); if (i == 0 && index) { // Re-use expr by extending the ASTindex. @@ -918,6 +922,14 @@ ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr, } args[0]->append (args[1]); args[1]->append (args[2]); + + if (allconst) { + // return a type constructor instead of a swizzle + ASSERT (!cleanup); + // initial expression will be unused + cleanup.reset (expr); + return new ASTtype_constructor (comp, type, args[0]); + } return new ASTswizzle (comp, args[0], field); } diff --git a/src/liboslcomp/ast.h b/src/liboslcomp/ast.h index 138b7055a..3d9f37c70 100644 --- a/src/liboslcomp/ast.h +++ b/src/liboslcomp/ast.h @@ -606,7 +606,8 @@ class ASTfieldselect : public ASTNode ustring m_fullname; ///< Full name of variable and field public: - static ASTNode* create (OSLCompilerImpl *comp, ASTNode *expr, ustring field); + static ASTNode* create (OSLCompilerImpl *comp, ASTNode *expr, ustring field, + bool swizzle = false); ustring field () const { return m_field; } ustring fullname () const { return m_fullname; } diff --git a/src/liboslcomp/oslgram.y b/src/liboslcomp/oslgram.y index 0bca41f6a..daeebc1f5 100644 --- a/src/liboslcomp/oslgram.y +++ b/src/liboslcomp/oslgram.y @@ -83,7 +83,7 @@ static std::stack typespec_stack; // just for function_declaration // Define the terminal symbols. -%token IDENTIFIER STRING_LITERAL +%token IDENTIFIER STRING_LITERAL SWIZZLE_IDENTIFIER %token INT_LITERAL %token FLOAT_LITERAL %token COLORTYPE FLOATTYPE INTTYPE MATRIXTYPE @@ -778,6 +778,10 @@ id_or_field { $$ = new ASTvariable_ref (oslcompiler, ustring($1)); } + | variable_lvalue SWIZZLE_IDENTIFIER + { + $$ = ASTfieldselect::create (oslcompiler, $1, ustring($2)); + } | variable_lvalue '.' IDENTIFIER { $$ = ASTfieldselect::create (oslcompiler, $1, ustring($3)); diff --git a/src/liboslcomp/osllex.l b/src/liboslcomp/osllex.l index 5f4ab1eaf..b9e1c6cae 100644 --- a/src/liboslcomp/osllex.l +++ b/src/liboslcomp/osllex.l @@ -80,6 +80,11 @@ STR \"(\\.|[^\\"\n])*\" /* " This extra quote fixes emacs syntax highlighting on this file */ /* Identifier: alphanumeric, may contain digits after the first character */ IDENT ({ALPHA}|[_])({ALPHA}|{DIGIT}|[_])* + /* Swizzle that starts with a constant value + Needs to include the . selector to take precedence over FLT */ +SWIZZLE (\.[01][01rgbxyz]{2}) + + /* C preprocessor (cpp) directives */ CPP ^[ \t]*#.*\n CPLUSCOMMENT \/\/.*\n @@ -196,6 +201,11 @@ void preprocess (const char *yytext); SETLINE; return IDENTIFIER; } +{SWIZZLE} { + yylval.s = ustring(yytext+1).c_str(); + SETLINE; + return SWIZZLE_IDENTIFIER; + } /* Literal values */ {INTEGER} { diff --git a/testsuite/oslc-err-swizzle/ref/out.txt b/testsuite/oslc-err-swizzle/ref/out.txt new file mode 100644 index 000000000..f5bdb7406 --- /dev/null +++ b/testsuite/oslc-err-swizzle/ref/out.txt @@ -0,0 +1,3 @@ +test.osl:7: error: Can't assign via = to something that isn't an lvalue +test.osl:8: error: Can't assign via = to something that isn't an lvalue +FAILED test.osl diff --git a/testsuite/oslc-err-swizzle/run.py b/testsuite/oslc-err-swizzle/run.py new file mode 100755 index 000000000..d901e097a --- /dev/null +++ b/testsuite/oslc-err-swizzle/run.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +# command = oslc("test.osl") +# don't even need that -- it's automatic +failureok = 1 # this test is expected to have oslc errors diff --git a/testsuite/oslc-err-swizzle/test.osl b/testsuite/oslc-err-swizzle/test.osl new file mode 100644 index 000000000..1700c29eb --- /dev/null +++ b/testsuite/oslc-err-swizzle/test.osl @@ -0,0 +1,10 @@ +// Error on invalid swizzle operations + +shader test () +{ + color c; + + c.rg0 = color(1); + c.01r = color(1); + // c.0; +} diff --git a/testsuite/swizzle/ref/out.txt b/testsuite/swizzle/ref/out.txt index cf493365e..d9435116c 100644 --- a/testsuite/swizzle/ref/out.txt +++ b/testsuite/swizzle/ref/out.txt @@ -6,6 +6,8 @@ c.r00: 1 0 0 c.g01: 2 0 1 c.b11: 3 1 1 c.bg1: 3 2 1 +c.01g: 0 1 2 +c.101: 1 0 1 c.rgb = c.brg: 3 1 2 c.rgb = c.brg: 2 3 1 c.rgb = c.brg: 1 2 3 diff --git a/testsuite/swizzle/swizzle.osl b/testsuite/swizzle/swizzle.osl index 65872e64d..828c1243f 100644 --- a/testsuite/swizzle/swizzle.osl +++ b/testsuite/swizzle/swizzle.osl @@ -4,6 +4,10 @@ shader swizzle () { + // Make sure floats don't generate a swizzle operation. + float noswizzle = 1.101; + noswizzle = 1.001; + color c = color(1,2,3); printf("c: %g\n", c); @@ -19,6 +23,8 @@ shader swizzle () printf("c.g01: %g\n", c.g01); printf("c.b11: %g\n", c.b11); printf("c.bg1: %g\n", c.bg1); + printf("c.01g: %g\n", c.01g); + printf("c.101: %g\n", c.101); c = c.brg; printf("c.rgb = c.brg: %g\n", c);