diff --git a/CMakeLists.txt b/CMakeLists.txt index 9acf8fe5fa..c7eb3abf48 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 ccf3862d41..497d17a63d 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 138b7055a7..3d9f37c700 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 0bca41f6aa..daeebc1f53 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 5f4ab1eaff..b9e1c6cae5 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 0000000000..f5bdb74064 --- /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 0000000000..d901e097a5 --- /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 0000000000..1700c29eb6 --- /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 cf493365e2..d9435116c3 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 65872e64df..828c1243fd 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);