added initial GLSL support to skslc
authorethannicholas <ethannicholas@google.com>
Wed, 3 Aug 2016 19:43:36 +0000 (12:43 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 3 Aug 2016 19:43:36 +0000 (12:43 -0700)
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2185393003

Review-Url: https://codereview.chromium.org/2185393003

31 files changed:
BUILD.gn
gyp/sksl.gypi
public.bzl
src/sksl/SkSLCodeGenerator.h
src/sksl/SkSLCompiler.cpp
src/sksl/SkSLCompiler.h
src/sksl/SkSLGLSLCodeGenerator.cpp [new file with mode: 0644]
src/sksl/SkSLGLSLCodeGenerator.h [new file with mode: 0644]
src/sksl/SkSLIRGenerator.cpp
src/sksl/SkSLParser.cpp
src/sksl/SkSLSPIRVCodeGenerator.cpp
src/sksl/SkSLSPIRVCodeGenerator.h
src/sksl/SkSLToken.h
src/sksl/SkSLUtil.h
src/sksl/ast/SkSLASTLayout.h
src/sksl/ast/SkSLASTModifiers.h
src/sksl/ast/SkSLASTNode.h
src/sksl/ir/SkSLBoolLiteral.h
src/sksl/ir/SkSLFieldAccess.h
src/sksl/ir/SkSLFloatLiteral.h
src/sksl/ir/SkSLFunctionReference.h
src/sksl/ir/SkSLIntLiteral.h
src/sksl/ir/SkSLLayout.h
src/sksl/ir/SkSLModifiers.h
src/sksl/ir/SkSLTypeReference.h
src/sksl/ir/SkSLUnresolvedFunction.h
src/sksl/ir/SkSLVarDeclaration.h
src/sksl/ir/SkSLVariable.h
src/sksl/lex.sksl.c
src/sksl/sksl.flex
tests/SkSLGLSLTest.cpp [new file with mode: 0644]

index 0780f1b..91c2b43 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -459,6 +459,7 @@ test_lib("tests") {
               rebase_path("tests/PathOpsSkpClipTest.cpp"),  # alternate main
               rebase_path("tests/RTConfRegistryTest.cpp"),  # TODO: delete
               rebase_path("tests/SkSLErrorTest.cpp"),   # TODO: make work
+              rebase_path("tests/SkSLGLSLTest.cpp"),   # TODO: make work
               rebase_path("tests/SkpSkGrTest.cpp"),  # doesn't compile
               rebase_path("tests/skia_test.cpp"),  # alternate main
             ]
index be2e715..8718c8a 100644 (file)
@@ -14,6 +14,7 @@
     '../src/sksl/SkSLCompiler.cpp',
     '../src/sksl/SkSLIRGenerator.cpp',
     '../src/sksl/SkSLParser.cpp',
+    '../src/sksl/SkSLGLSLCodeGenerator.cpp',
     '../src/sksl/SkSLSPIRVCodeGenerator.cpp',
     '../src/sksl/SkSLUtil.cpp',
     '../src/sksl/ir/SkSLSymbolTable.cpp',
index 5734888..36896f7 100644 (file)
@@ -435,7 +435,7 @@ DM_SRCS_ALL = struct(
         "tests/PathOpsSkpClipTest.cpp",  # Alternate main.
         "tests/skia_test.cpp",  # Old main.
         "tests/SkpSkGrTest.cpp",  # Alternate main.
-        "tests/SkSLErrorTest.cpp",  # Excluded along with Vulkan.
+        "tests/SkSL*.cpp",  # Excluded along with Vulkan.
         "tests/SVGDeviceTest.cpp",
         "tools/gpu/gl/angle/*",
         "tools/gpu/gl/command_buffer/*",
index cd50cc8..7fa8c19 100644 (file)
@@ -20,9 +20,9 @@ namespace SkSL {
  */
 class CodeGenerator {
 public:
-       virtual ~CodeGenerator() {}
-       
-    virtual void generateCode(Program& program, std::ostream& out) = 0;
+    virtual ~CodeGenerator() {}
+    
+    virtual void generateCode(const Program& program, std::ostream& out) = 0;
 };
 
 } // namespace
index 0d65b10..f55150c 100644 (file)
@@ -67,14 +67,17 @@ Compiler::Compiler()
     ADD_TYPE(BVec3);
     ADD_TYPE(BVec4);
     ADD_TYPE(Mat2x2);
+    types->addWithoutOwnership("mat2x2", fContext.fMat2x2_Type.get());
     ADD_TYPE(Mat2x3);
     ADD_TYPE(Mat2x4);
     ADD_TYPE(Mat3x2);
     ADD_TYPE(Mat3x3);
+    types->addWithoutOwnership("mat3x3", fContext.fMat3x3_Type.get());
     ADD_TYPE(Mat3x4);
     ADD_TYPE(Mat4x2);
     ADD_TYPE(Mat4x3);
     ADD_TYPE(Mat4x4);
+    types->addWithoutOwnership("mat4x4", fContext.fMat4x4_Type.get());
     ADD_TYPE(GenType);
     ADD_TYPE(GenDType);
     ADD_TYPE(GenIType);
@@ -223,8 +226,7 @@ void Compiler::writeErrorCount() {
     }
 }
 
-#include <fstream>
-bool Compiler::toSPIRV(Program::Kind kind, std::string text, std::ostream& out) {
+bool Compiler::toSPIRV(Program::Kind kind, const std::string& text, std::ostream& out) {
     auto program = this->convertProgram(kind, text);
     if (fErrorCount == 0) {
         SkSL::SPIRVCodeGenerator cg(&fContext);
@@ -234,13 +236,34 @@ bool Compiler::toSPIRV(Program::Kind kind, std::string text, std::ostream& out)
     return fErrorCount == 0;
 }
 
-bool Compiler::toSPIRV(Program::Kind kind, std::string text, std::string* out) {
+bool Compiler::toSPIRV(Program::Kind kind, const std::string& text, std::string* out) {
     std::stringstream buffer;
     bool result = this->toSPIRV(kind, text, buffer);
     if (result) {
         *out = buffer.str();
     }
+    return result;
+}
+
+bool Compiler::toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, 
+                      std::ostream& out) {
+    auto program = this->convertProgram(kind, text);
+    if (fErrorCount == 0) {
+        SkSL::GLSLCodeGenerator cg(&fContext, caps);
+        cg.generateCode(*program.get(), out);
+        ASSERT(!out.rdstate());
+    }
     return fErrorCount == 0;
 }
 
+bool Compiler::toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, 
+                      std::string* out) {
+    std::stringstream buffer;
+    bool result = this->toGLSL(kind, text, caps, buffer);
+    if (result) {
+        *out = buffer.str();
+    }
+    return result;
+}
+
 } // namespace
index e63d5f4..9cd1eac 100644 (file)
@@ -13,6 +13,7 @@
 #include "ir/SkSLSymbolTable.h"
 #include "SkSLContext.h"
 #include "SkSLErrorReporter.h"
+#include "SkSLGLSLCodeGenerator.h"
 
 namespace SkSL {
 
@@ -32,9 +33,13 @@ public:
 
     std::unique_ptr<Program> convertProgram(Program::Kind kind, std::string text);
 
-       bool toSPIRV(Program::Kind kind, std::string text, std::ostream& out);
-       
-       bool toSPIRV(Program::Kind kind, std::string text, std::string* out);
+    bool toSPIRV(Program::Kind kind, const std::string& text, std::ostream& out);
+    
+    bool toSPIRV(Program::Kind kind, const std::string& text, std::string* out);
+
+    bool toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, std::ostream& out);
+    
+    bool toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, std::string* out);
 
     void error(Position position, std::string msg) override;
 
@@ -45,7 +50,7 @@ public:
 private:
 
     void internalConvertProgram(std::string text,
-                                                       std::vector<std::unique_ptr<ProgramElement>>* result);
+                                std::vector<std::unique_ptr<ProgramElement>>* result);
 
     std::shared_ptr<SymbolTable> fTypes;
     IRGenerator* fIRGenerator;
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
new file mode 100644 (file)
index 0000000..8e69a2f
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkSLGLSLCodeGenerator.h"
+
+#include "string.h"
+
+#include "GLSL.std.450.h"
+
+#include "ir/SkSLExpressionStatement.h"
+#include "ir/SkSLExtension.h"
+#include "ir/SkSLIndexExpression.h"
+#include "ir/SkSLVariableReference.h"
+
+namespace SkSL {
+
+void GLSLCodeGenerator::write(const char* s) {
+    if (s[0] == 0) {
+        return;
+    }
+    if (fAtLineStart) {
+        for (int i = 0; i < fIndentation; i++) {
+            *fOut << "    ";
+        }
+    }
+    *fOut << s;
+    fAtLineStart = false;
+}
+
+void GLSLCodeGenerator::writeLine(const char* s) {
+    this->write(s);
+    *fOut << "\n";
+    fAtLineStart = true;
+}
+
+void GLSLCodeGenerator::write(const std::string& s) {
+    this->write(s.c_str());
+}
+
+void GLSLCodeGenerator::writeLine(const std::string& s) {
+    this->writeLine(s.c_str());
+}
+
+void GLSLCodeGenerator::writeLine() {
+    this->writeLine("");
+}
+
+void GLSLCodeGenerator::writeExtension(const Extension& ext) {
+    this->writeLine("#extension " + ext.fName + " : enable");
+}
+
+void GLSLCodeGenerator::writeType(const Type& type) {
+    if (type.kind() == Type::kStruct_Kind) {
+        for (const Type* search : fWrittenStructs) {
+            if (*search == type) {
+                // already written
+                this->write(type.name());
+                return;
+            }
+        }
+        fWrittenStructs.push_back(&type);
+        this->writeLine("struct " + type.name() + " {");
+        fIndentation++;
+        for (const auto& f : type.fields()) {
+            this->writeModifiers(f.fModifiers);
+            // sizes (which must be static in structs) are part of the type name here
+            this->writeType(f.fType);
+            this->writeLine(" " + f.fName + ";");
+        }
+        fIndentation--;
+        this->writeLine("}");
+    } else {
+        this->write(type.name());
+    }
+}
+
+void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
+    switch (expr.fKind) {
+        case Expression::kBinary_Kind:
+            this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
+            break;
+        case Expression::kBoolLiteral_Kind:
+            this->writeBoolLiteral((BoolLiteral&) expr);
+            break;
+        case Expression::kConstructor_Kind:
+            this->writeConstructor((Constructor&) expr);
+            break;
+        case Expression::kIntLiteral_Kind:
+            this->writeIntLiteral((IntLiteral&) expr);
+            break;
+        case Expression::kFieldAccess_Kind:
+            this->writeFieldAccess(((FieldAccess&) expr));
+            break;
+        case Expression::kFloatLiteral_Kind:
+            this->writeFloatLiteral(((FloatLiteral&) expr));
+            break;
+        case Expression::kFunctionCall_Kind:
+            this->writeFunctionCall((FunctionCall&) expr);
+            break;
+        case Expression::kPrefix_Kind:
+            this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
+            break;
+        case Expression::kPostfix_Kind:
+            this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
+            break;
+        case Expression::kSwizzle_Kind:
+            this->writeSwizzle((Swizzle&) expr);
+            break;
+        case Expression::kVariableReference_Kind:
+            this->writeVariableReference((VariableReference&) expr);
+            break;
+        case Expression::kTernary_Kind:
+            this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
+            break;
+        case Expression::kIndex_Kind:
+            this->writeIndexExpression((IndexExpression&) expr);
+            break;
+        default:
+            ABORT("unsupported expression: %s", expr.description().c_str());
+    }
+}
+
+void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
+    this->write(c.fFunction.fName + "(");
+    const char* separator = "";
+    for (const auto& arg : c.fArguments) {
+        this->write(separator);
+        separator = ", ";
+        this->writeExpression(*arg, kSequence_Precedence);
+    }
+    this->write(")");
+}
+
+void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
+    this->write(c.fType.name() + "(");
+    const char* separator = "";
+    for (const auto& arg : c.fArguments) {
+        this->write(separator);
+        separator = ", ";
+        this->writeExpression(*arg, kSequence_Precedence);
+    }
+    this->write(")");
+}
+
+void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
+    this->write(ref.fVariable.fName);
+}
+
+void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
+    this->writeExpression(*expr.fBase, kPostfix_Precedence);
+    this->write("[");
+    this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
+    this->write("]");
+}
+
+void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
+    if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
+        this->writeExpression(*f.fBase, kPostfix_Precedence);
+        this->write(".");
+    }
+    this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
+}
+
+void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
+    this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
+    this->write(".");
+    for (int c : swizzle.fComponents) {
+        this->write(&("x\0y\0z\0w\0"[c * 2]));
+    }
+}
+
+static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
+    switch (op) {
+        case Token::STAR:         // fall through
+        case Token::SLASH:        // fall through
+        case Token::PERCENT:      return GLSLCodeGenerator::kMultiplicative_Precedence;
+        case Token::PLUS:         // fall through
+        case Token::MINUS:        return GLSLCodeGenerator::kAdditive_Precedence;
+        case Token::SHL:          // fall through
+        case Token::SHR:          return GLSLCodeGenerator::kShift_Precedence;
+        case Token::LT:           // fall through
+        case Token::GT:           // fall through
+        case Token::LTEQ:         // fall through
+        case Token::GTEQ:         return GLSLCodeGenerator::kRelational_Precedence;
+        case Token::EQEQ:         // fall through
+        case Token::NEQ:          return GLSLCodeGenerator::kEquality_Precedence;
+        case Token::BITWISEAND:   return GLSLCodeGenerator::kBitwiseAnd_Precedence;
+        case Token::BITWISEXOR:   return GLSLCodeGenerator::kBitwiseXor_Precedence;
+        case Token::BITWISEOR:    return GLSLCodeGenerator::kBitwiseOr_Precedence;
+        case Token::LOGICALAND:   return GLSLCodeGenerator::kLogicalAnd_Precedence;
+        case Token::LOGICALXOR:   return GLSLCodeGenerator::kLogicalXor_Precedence;
+        case Token::LOGICALOR:    return GLSLCodeGenerator::kLogicalOr_Precedence;
+        case Token::EQ:           // fall through
+        case Token::PLUSEQ:       // fall through
+        case Token::MINUSEQ:      // fall through
+        case Token::STAREQ:       // fall through
+        case Token::SLASHEQ:      // fall through
+        case Token::PERCENTEQ:    // fall through
+        case Token::SHLEQ:        // fall through
+        case Token::SHREQ:        // fall through
+        case Token::LOGICALANDEQ: // fall through
+        case Token::LOGICALXOREQ: // fall through
+        case Token::LOGICALOREQ:  // fall through
+        case Token::BITWISEANDEQ: // fall through
+        case Token::BITWISEXOREQ: // fall through
+        case Token::BITWISEOREQ:  return GLSLCodeGenerator::kAssignment_Precedence;
+        default: ABORT("unsupported binary operator");
+    }
+}
+
+void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b, 
+                                              Precedence parentPrecedence) {
+    Precedence precedence = get_binary_precedence(b.fOperator);
+    if (precedence >= parentPrecedence) {
+        this->write("(");
+    }
+    this->writeExpression(*b.fLeft, precedence);
+    this->write(" " + Token::OperatorName(b.fOperator) + " ");
+    this->writeExpression(*b.fRight, precedence);
+    if (precedence >= parentPrecedence) {
+        this->write(")");
+    }
+}
+
+void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t, 
+                                               Precedence parentPrecedence) {
+    if (kTernary_Precedence >= parentPrecedence) {
+        this->write("(");
+    }
+    this->writeExpression(*t.fTest, kTernary_Precedence);
+    this->write(" ? ");
+    this->writeExpression(*t.fIfTrue, kTernary_Precedence);
+    this->write(" : ");
+    this->writeExpression(*t.fIfFalse, kTernary_Precedence);
+    if (kTernary_Precedence >= parentPrecedence) {
+        this->write(")");
+    }
+}
+
+void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p, 
+                                              Precedence parentPrecedence) {
+    if (kPrefix_Precedence >= parentPrecedence) {
+        this->write("(");
+    }
+    this->write(Token::OperatorName(p.fOperator));
+    this->writeExpression(*p.fOperand, kPrefix_Precedence);
+    if (kPrefix_Precedence >= parentPrecedence) {
+        this->write(")");
+    }
+}
+
+void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p, 
+                                               Precedence parentPrecedence) {
+    if (kPostfix_Precedence >= parentPrecedence) {
+        this->write("(");
+    }
+    this->writeExpression(*p.fOperand, kPostfix_Precedence);
+    this->write(Token::OperatorName(p.fOperator));
+    if (kPostfix_Precedence >= parentPrecedence) {
+        this->write(")");
+    }
+}
+
+void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
+    this->write(b.fValue ? "true" : "false");
+}
+
+void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
+    this->write(to_string(i.fValue));
+}
+
+void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
+    this->write(to_string(f.fValue));
+}
+
+void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
+    this->writeType(f.fDeclaration.fReturnType);
+    this->write(" " + f.fDeclaration.fName + "(");
+    const char* separator = "";
+    for (const auto& param : f.fDeclaration.fParameters) {
+        this->write(separator);
+        separator = ", ";
+        this->writeModifiers(param->fModifiers);
+        this->writeType(param->fType);
+        this->write(" " + param->fName);
+    }
+    this->write(") ");
+    this->writeBlock(*f.fBody);
+    this->writeLine();
+}
+
+void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers) {
+    this->write(modifiers.description());
+}
+
+void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
+    if (intf.fVariable.fName == "gl_PerVertex") {
+        return;
+    }
+    this->writeModifiers(intf.fVariable.fModifiers);
+    this->writeLine(intf.fVariable.fType.name() + " {");
+    fIndentation++;
+    for (const auto& f : intf.fVariable.fType.fields()) {
+        this->writeModifiers(f.fModifiers);
+        this->writeType(f.fType);
+        this->writeLine(" " + f.fName + ";");
+    }
+    fIndentation--;
+    this->writeLine("};");
+}
+
+void GLSLCodeGenerator::writeVarDeclaration(const VarDeclaration& decl) {
+    ASSERT(decl.fVars.size() > 0);
+    this->writeModifiers(decl.fVars[0]->fModifiers);
+    this->writeType(decl.fBaseType);
+    std::string separator = " ";
+    for (size_t i = 0; i < decl.fVars.size(); i++) {
+        ASSERT(decl.fVars[i]->fModifiers == decl.fVars[0]->fModifiers);
+        this->write(separator);
+        separator = ", ";
+        this->write(decl.fVars[i]->fName);
+        for (const auto& size : decl.fSizes[i]) {
+            this->write("[");
+            this->writeExpression(*size, kTopLevel_Precedence);
+            this->write("]");
+        }
+        if (decl.fValues[i]) {
+            this->write(" = ");
+            this->writeExpression(*decl.fValues[i], kTopLevel_Precedence);
+        }
+    }
+    this->write(";");
+}
+
+void GLSLCodeGenerator::writeStatement(const Statement& s) {
+    switch (s.fKind) {
+        case Statement::kBlock_Kind:
+            this->writeBlock((Block&) s);
+            break;
+        case Statement::kExpression_Kind:
+            this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
+            this->write(";");
+            break;
+        case Statement::kReturn_Kind: 
+            this->writeReturnStatement((ReturnStatement&) s);
+            break;
+        case Statement::kVarDeclaration_Kind:
+            this->writeVarDeclaration(*((VarDeclarationStatement&) s).fDeclaration);
+            break;
+        case Statement::kIf_Kind:
+            this->writeIfStatement((IfStatement&) s);
+            break;
+        case Statement::kFor_Kind:
+            this->writeForStatement((ForStatement&) s);
+            break;
+        case Statement::kWhile_Kind:
+            this->writeWhileStatement((WhileStatement&) s);
+            break;
+        case Statement::kDo_Kind:
+            this->writeDoStatement((DoStatement&) s);
+            break;
+        case Statement::kBreak_Kind:
+            this->write("break;");
+            break;
+        case Statement::kContinue_Kind:
+            this->write("continue;");
+            break;
+        case Statement::kDiscard_Kind:
+            this->write("discard;");
+            break;
+        default:
+            ABORT("unsupported statement: %s", s.description().c_str());
+    }
+}
+
+void GLSLCodeGenerator::writeBlock(const Block& b) {
+    this->writeLine("{");
+    fIndentation++;
+    for (const auto& s : b.fStatements) {
+        this->writeStatement(*s);
+        this->writeLine();
+    }
+    fIndentation--;
+    this->write("}");
+}
+
+void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
+    this->write("if (");
+    this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
+    this->write(") ");
+    this->writeStatement(*stmt.fIfTrue);
+    if (stmt.fIfFalse) {
+        this->write(" else ");
+        this->writeStatement(*stmt.fIfFalse);
+    }
+}
+
+void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
+    this->write("for (");
+    if (f.fInitializer) {
+        this->writeStatement(*f.fInitializer);
+    } else {
+        this->write("; ");
+    }
+    if (f.fTest) {
+        this->writeExpression(*f.fTest, kTopLevel_Precedence);
+    }
+    this->write("; ");
+    if (f.fNext) {
+        this->writeExpression(*f.fNext, kTopLevel_Precedence);
+    }
+    this->write(") ");
+    this->writeStatement(*f.fStatement);
+}
+
+void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
+    this->write("while (");
+    this->writeExpression(*w.fTest, kTopLevel_Precedence);
+    this->write(") ");
+    this->writeStatement(*w.fStatement);
+}
+
+void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
+    this->write("do ");
+    this->writeStatement(*d.fStatement);
+    this->write(" while (");
+    this->writeExpression(*d.fTest, kTopLevel_Precedence);
+    this->write(");");
+}
+
+void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
+    this->write("return");
+    if (r.fExpression) {
+        this->write(" ");
+        this->writeExpression(*r.fExpression, kTopLevel_Precedence);
+    }
+    this->write(";");
+}
+
+void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) {
+    ASSERT(fOut == nullptr);
+    fOut = &out;
+    this->write("#version " + to_string(fCaps.fVersion));
+    if (fCaps.fStandard == GLCaps::kGLES_Standard) {
+        this->write(" es");
+    }
+    this->writeLine();
+    for (const auto& e : program.fElements) {
+        switch (e->fKind) {
+            case ProgramElement::kExtension_Kind:
+                this->writeExtension((Extension&) *e);
+                break;
+            case ProgramElement::kVar_Kind: {
+                VarDeclaration& decl = (VarDeclaration&) *e;
+                if (decl.fVars.size() > 0 && decl.fVars[0]->fModifiers.fLayout.fBuiltin == -1) {
+                    this->writeVarDeclaration(decl);
+                    this->writeLine();
+                }
+                break;
+            }
+            case ProgramElement::kInterfaceBlock_Kind:
+                this->writeInterfaceBlock((InterfaceBlock&) *e);
+                break;
+            case ProgramElement::kFunction_Kind:
+                this->writeFunction((FunctionDefinition&) *e);
+                break;
+            default:
+                printf("%s\n", e->description().c_str());
+                ABORT("unsupported program element");
+        }
+    }
+    fOut = nullptr;
+}
+
+}
diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h
new file mode 100644 (file)
index 0000000..76512e0
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SKSL_GLSLCODEGENERATOR
+#define SKSL_GLSLCODEGENERATOR
+
+#include <stack>
+#include <tuple>
+#include <unordered_map>
+
+#include "SkSLCodeGenerator.h"
+#include "ir/SkSLBinaryExpression.h"
+#include "ir/SkSLBoolLiteral.h"
+#include "ir/SkSLConstructor.h"
+#include "ir/SkSLDoStatement.h"
+#include "ir/SkSLExtension.h"
+#include "ir/SkSLFloatLiteral.h"
+#include "ir/SkSLIfStatement.h"
+#include "ir/SkSLIndexExpression.h"
+#include "ir/SkSLInterfaceBlock.h"
+#include "ir/SkSLIntLiteral.h"
+#include "ir/SkSLFieldAccess.h"
+#include "ir/SkSLForStatement.h"
+#include "ir/SkSLFunctionCall.h"
+#include "ir/SkSLFunctionDeclaration.h"
+#include "ir/SkSLFunctionDefinition.h"
+#include "ir/SkSLPrefixExpression.h"
+#include "ir/SkSLPostfixExpression.h"
+#include "ir/SkSLProgramElement.h"
+#include "ir/SkSLReturnStatement.h"
+#include "ir/SkSLStatement.h"
+#include "ir/SkSLSwizzle.h"
+#include "ir/SkSLTernaryExpression.h"
+#include "ir/SkSLVarDeclaration.h"
+#include "ir/SkSLVarDeclarationStatement.h"
+#include "ir/SkSLVariableReference.h"
+#include "ir/SkSLWhileStatement.h"
+
+namespace SkSL {
+
+#define kLast_Capability SpvCapabilityMultiViewport
+
+struct GLCaps {
+    int fVersion;
+    enum {
+        kGL_Standard,
+        kGLES_Standard
+    } fStandard;
+};
+
+/**
+ * Converts a Program into GLSL code.
+ */
+class GLSLCodeGenerator : public CodeGenerator {
+public:
+    enum Precedence {
+        kParentheses_Precedence    =  1,
+        kPostfix_Precedence        =  2,
+        kPrefix_Precedence         =  3,
+        kMultiplicative_Precedence =  4,
+        kAdditive_Precedence       =  5,
+        kShift_Precedence          =  6,
+        kRelational_Precedence     =  7,
+        kEquality_Precedence       =  8,
+        kBitwiseAnd_Precedence     =  9,
+        kBitwiseXor_Precedence     = 10,
+        kBitwiseOr_Precedence      = 11,
+        kLogicalAnd_Precedence     = 12,
+        kLogicalXor_Precedence     = 13,
+        kLogicalOr_Precedence      = 14,
+        kTernary_Precedence        = 15,
+        kAssignment_Precedence     = 16,
+        kSequence_Precedence       = 17,
+        kTopLevel_Precedence       = 18
+    };
+
+    GLSLCodeGenerator(const Context* context, GLCaps caps)
+    : fContext(*context)
+    , fCaps(caps)
+    , fIndentation(0)
+    , fAtLineStart(true) {}
+
+    void generateCode(const Program& program, std::ostream& out) override;
+
+private:
+    void write(const char* s);
+
+    void writeLine();
+
+    void writeLine(const char* s);
+
+    void write(const std::string& s);
+
+    void writeLine(const std::string& s);
+
+    void writeType(const Type& type);
+
+    void writeExtension(const Extension& ext);
+
+    void writeInterfaceBlock(const InterfaceBlock& intf);
+
+    void writeFunctionStart(const FunctionDeclaration& f);
+    
+    void writeFunctionDeclaration(const FunctionDeclaration& f);
+
+    void writeFunction(const FunctionDefinition& f);
+
+    void writeLayout(const Layout& layout);
+
+    void writeModifiers(const Modifiers& modifiers);
+    
+    void writeGlobalVars(const VarDeclaration& vs);
+
+    void writeVarDeclaration(const VarDeclaration& decl);
+
+    void writeVariableReference(const VariableReference& ref);
+
+    void writeExpression(const Expression& expr, Precedence parentPrecedence);
+    
+    void writeIntrinsicCall(const FunctionCall& c);
+
+    void writeFunctionCall(const FunctionCall& c);
+
+    void writeConstructor(const Constructor& c);
+
+    void writeFieldAccess(const FieldAccess& f);
+
+    void writeSwizzle(const Swizzle& swizzle);
+
+    void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
+
+    void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
+
+    void writeIndexExpression(const IndexExpression& expr);
+
+    void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
+
+    void writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence);
+
+    void writeBoolLiteral(const BoolLiteral& b);
+
+    void writeIntLiteral(const IntLiteral& i);
+
+    void writeFloatLiteral(const FloatLiteral& f);
+
+    void writeStatement(const Statement& s);
+
+    void writeBlock(const Block& b);
+
+    void writeIfStatement(const IfStatement& stmt);
+
+    void writeForStatement(const ForStatement& f);
+
+    void writeWhileStatement(const WhileStatement& w);
+
+    void writeDoStatement(const DoStatement& d);
+
+    void writeReturnStatement(const ReturnStatement& r);
+
+    const Context& fContext;
+    const GLCaps fCaps;
+    std::ostream* fOut;
+    int fIndentation;
+    bool fAtLineStart;
+    // Keeps track of which struct types we have written. Given that we are unlikely to ever write 
+    // more than one or two structs per shader, a simple linear search will be faster than anything 
+    // fancier.
+    std::vector<const Type*> fWrittenStructs;
+};
+
+}
+
+#endif
index f250c4b..db033d6 100644 (file)
@@ -182,7 +182,6 @@ std::unique_ptr<VarDeclaration> IRGenerator::convertVarDeclaration(const ASTVarD
                 currentVarSizes.push_back(nullptr);
             }
         }
-        sizes.push_back(std::move(currentVarSizes));
         auto var = std::unique_ptr<Variable>(new Variable(decl.fPosition, modifiers, decl.fNames[i], 
                                                           *type, storage));
         std::unique_ptr<Expression> value;
@@ -193,12 +192,22 @@ std::unique_ptr<VarDeclaration> IRGenerator::convertVarDeclaration(const ASTVarD
             }
             value = this->coerce(std::move(value), *type);
         }
-        variables.push_back(var.get());
-        fSymbolTable->add(decl.fNames[i], std::move(var));
-        values.push_back(std::move(value));
+        if ("gl_FragCoord" == decl.fNames[i] && (*fSymbolTable)[decl.fNames[i]]) {
+            // already defined, just update the modifiers
+            Variable* old = (Variable*) (*fSymbolTable)[decl.fNames[i]];
+            old->fModifiers = var->fModifiers;
+        } else {
+            variables.push_back(var.get());
+            fSymbolTable->add(decl.fNames[i], std::move(var));
+            values.push_back(std::move(value));
+            sizes.push_back(std::move(currentVarSizes));
+        }
     }
-    return std::unique_ptr<VarDeclaration>(new VarDeclaration(decl.fPosition, std::move(variables), 
-                                                              std::move(sizes), std::move(values)));
+    return std::unique_ptr<VarDeclaration>(new VarDeclaration(decl.fPosition, 
+                                                              baseType,
+                                                              std::move(variables), 
+                                                              std::move(sizes), 
+                                                              std::move(values)));
 }
 
 std::unique_ptr<Statement> IRGenerator::convertIf(const ASTIfStatement& s) {
@@ -573,8 +582,10 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTIdentifier&
         case Symbol::kField_Kind: {
             const Field* field = (const Field*) result;
             VariableReference* base = new VariableReference(identifier.fPosition, field->fOwner);
-            return std::unique_ptr<Expression>(new FieldAccess(std::unique_ptr<Expression>(base),
-                                                               field->fFieldIndex));
+            return std::unique_ptr<Expression>(new FieldAccess(
+                                                  std::unique_ptr<Expression>(base),
+                                                  field->fFieldIndex,
+                                                  FieldAccess::kAnonymousInterfaceBlock_OwnerKind));
         }
         case Symbol::kType_Kind: {
             const Type* t = (const Type*) result;
@@ -616,6 +627,12 @@ std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr
           type.description().c_str());
 }
 
+static bool is_matrix_multiply(const Type& left, const Type& right) {
+    if (left.kind() == Type::kMatrix_Kind) {
+        return right.kind() == Type::kMatrix_Kind || right.kind() == Type::kVector_Kind;
+    }
+    return left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind;
+}
 /**
  * Determines the operand and result types of a binary expression. Returns true if the expression is
  * legal, false otherwise. If false, the values of the out parameters are undefined.
@@ -651,18 +668,41 @@ static bool determine_binary_type(const Context& context,
                    right.canCoerceTo(*context.fBool_Type);
         case Token::STAR: // fall through
         case Token::STAREQ: 
-            // FIXME need to handle non-square matrices
-            if (left.kind() == Type::kMatrix_Kind && right.kind() == Type::kVector_Kind) {
-                *outLeftType = &left;
-                *outRightType = &right;
-                *outResultType = &right;
-                return left.rows() == right.columns();
-            }  
-            if (left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind) {
-                *outLeftType = &left;
-                *outRightType = &right;
-                *outResultType = &left;
-                return left.columns() == right.columns();
+            if (is_matrix_multiply(left, right)) {
+                // determine final component type
+                if (determine_binary_type(context, Token::STAR, left.componentType(),
+                                          right.componentType(), outLeftType, outRightType,
+                                          outResultType, false)) {
+                    *outLeftType = &(*outResultType)->toCompound(context, left.columns(), 
+                                                                 left.rows());;
+                    *outRightType = &(*outResultType)->toCompound(context, right.columns(), 
+                                                                  right.rows());;
+                    int leftColumns = left.columns();
+                    int leftRows = left.rows();
+                    int rightColumns;
+                    int rightRows;
+                    if (right.kind() == Type::kVector_Kind) {
+                        // matrix * vector treats the vector as a column vector, so we need to
+                        // transpose it
+                        rightColumns = right.rows();
+                        rightRows = right.columns();
+                        ASSERT(rightColumns == 1);
+                    } else {
+                        rightColumns = right.columns();
+                        rightRows = right.rows();
+                    }
+                    if (rightColumns > 1) {
+                        *outResultType = &(*outResultType)->toCompound(context, rightColumns,
+                                                                       leftRows);
+                    } else {
+                        // result was a column vector, transpose it back to a row
+                        *outResultType = &(*outResultType)->toCompound(context, leftRows,
+                                                                       rightColumns);
+                    }
+                    return leftColumns == rightRows;
+                } else {
+                    return false;
+                }
             }
             // fall through
         default:
index edff0c6..d6acc7d 100644 (file)
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
 #pragma clang diagnostic ignored "-Wnull-conversion"
+#pragma clang diagnostic ignored "-Wsign-compare"
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#endif
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4018)
 #endif
 #include "lex.sksl.c"
 #ifdef __clang__
 #pragma clang diagnostic pop
 #endif
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
 #undef register
 
 #include "ast/SkSLASTBinaryExpression.h"
@@ -471,10 +486,11 @@ ASTLayout Parser::layout() {
     int index = -1;
     int set = -1;
     int builtin = -1;
+    bool originUpperLeft = false;
     if (this->peek().fKind == Token::LAYOUT) {
         this->nextToken();
         if (!this->expect(Token::LPAREN, "'('")) {
-            return ASTLayout(location, binding, index, set, builtin);
+            return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
         }
         for (;;) {
             Token t = this->nextToken();
@@ -488,6 +504,8 @@ ASTLayout Parser::layout() {
                 set = this->layoutInt();
             } else if (t.fText == "builtin") {
                 builtin = this->layoutInt();
+            } else if (t.fText == "origin_upper_left") {
+                originUpperLeft = true;
             } else {
                 this->error(t.fPosition, ("'" + t.fText + 
                                           "' is not a valid layout qualifier").c_str());
@@ -501,11 +519,10 @@ ASTLayout Parser::layout() {
             }
         }
     }
-    return ASTLayout(location, binding, index, set, builtin);
+    return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
 }
 
-/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | 
-   MEDIUMP | HIGHP)* */
+/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */
 ASTModifiers Parser::modifiers() {
     ASTLayout layout = this->layout();
     int flags = 0;
@@ -545,6 +562,14 @@ ASTModifiers Parser::modifiers() {
                 this->nextToken();
                 flags |= ASTModifiers::kHighp_Flag;
                 break;
+            case Token::FLAT:
+                this->nextToken();
+                flags |= ASTModifiers::kFlat_Flag;
+                break;
+            case Token::NOPERSPECTIVE:
+                this->nextToken();
+                flags |= ASTModifiers::kNoPerspective_Flag;
+                break;
             default:
                 return ASTModifiers(layout, flags);
         }
index 2771e02..8a38cf7 100644 (file)
@@ -1151,7 +1151,7 @@ SpvId SPIRVCodeGenerator::getPointerType(const Type& type,
     return entry->second;
 }
 
-SpvId SPIRVCodeGenerator::writeExpression(Expression& expr, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, std::ostream& out) {
     switch (expr.fKind) {
         case Expression::kBinary_Kind:
             return this->writeBinaryExpression((BinaryExpression&) expr, out);
@@ -1185,7 +1185,7 @@ SpvId SPIRVCodeGenerator::writeExpression(Expression& expr, std::ostream& out) {
     return -1;
 }
 
-SpvId SPIRVCodeGenerator::writeIntrinsicCall(FunctionCall& c, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, std::ostream& out) {
     auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
     ASSERT(intrinsic != fIntrinsicMap.end());
     const Type& type = c.fArguments[0]->fType;
@@ -1240,7 +1240,7 @@ SpvId SPIRVCodeGenerator::writeIntrinsicCall(FunctionCall& c, std::ostream& out)
     }
 }
 
-SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(FunctionCall& c, SpecialIntrinsic kind, 
+SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, 
                                                 std::ostream& out) {
     SpvId result = this->nextId();
     switch (kind) {
@@ -1305,7 +1305,7 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(FunctionCall& c, SpecialIntrinsi
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeFunctionCall(FunctionCall& c, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, std::ostream& out) {
     const auto& entry = fFunctionMap.find(&c.fFunction);
     if (entry == fFunctionMap.end()) {
         return this->writeIntrinsicCall(c, out);
@@ -1366,7 +1366,7 @@ SpvId SPIRVCodeGenerator::writeFunctionCall(FunctionCall& c, std::ostream& out)
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeConstantVector(Constructor& c) {
+SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
     ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
     SpvId result = this->nextId();
     std::vector<SpvId> arguments;
@@ -1394,7 +1394,7 @@ SpvId SPIRVCodeGenerator::writeConstantVector(Constructor& c) {
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeFloatConstructor(Constructor& c, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, std::ostream& out) {
     ASSERT(c.fType == *fContext.fFloat_Type);
     ASSERT(c.fArguments.size() == 1);
     ASSERT(c.fArguments[0]->fType.isNumber());
@@ -1412,7 +1412,7 @@ SpvId SPIRVCodeGenerator::writeFloatConstructor(Constructor& c, std::ostream& ou
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeIntConstructor(Constructor& c, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, std::ostream& out) {
     ASSERT(c.fType == *fContext.fInt_Type);
     ASSERT(c.fArguments.size() == 1);
     ASSERT(c.fArguments[0]->fType.isNumber());
@@ -1430,7 +1430,7 @@ SpvId SPIRVCodeGenerator::writeIntConstructor(Constructor& c, std::ostream& out)
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeMatrixConstructor(Constructor& c, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, std::ostream& out) {
     ASSERT(c.fType.kind() == Type::kMatrix_Kind);
     // go ahead and write the arguments so we don't try to write new instructions in the middle of
     // an instruction
@@ -1502,7 +1502,7 @@ SpvId SPIRVCodeGenerator::writeMatrixConstructor(Constructor& c, std::ostream& o
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeVectorConstructor(Constructor& c, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, std::ostream& out) {
     ASSERT(c.fType.kind() == Type::kVector_Kind);
     if (c.isConstant()) {
         return this->writeConstantVector(c);
@@ -1532,7 +1532,7 @@ SpvId SPIRVCodeGenerator::writeVectorConstructor(Constructor& c, std::ostream& o
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeConstructor(Constructor& c, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, std::ostream& out) {
     if (c.fType == *fContext.fFloat_Type) {
         return this->writeFloatConstructor(c, out);
     } else if (c.fType == *fContext.fInt_Type) {
@@ -1560,7 +1560,7 @@ SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
     }
 }
 
-SpvStorageClass_ get_storage_class(Expression& expr) {
+SpvStorageClass_ get_storage_class(const Expression& expr) {
     switch (expr.fKind) {
         case Expression::kVariableReference_Kind:
             return get_storage_class(((VariableReference&) expr).fVariable.fModifiers);
@@ -1573,7 +1573,7 @@ SpvStorageClass_ get_storage_class(Expression& expr) {
     }
 }
 
-std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(Expression& expr, std::ostream& out) {
+std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, std::ostream& out) {
     std::vector<SpvId> chain;
     switch (expr.fKind) {
         case Expression::kIndex_Kind: {
@@ -1697,7 +1697,7 @@ private:
     const Type& fSwizzleType;
 };
 
-std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(Expression& expr, 
+std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr, 
                                                                           std::ostream& out) {
     switch (expr.fKind) {
         case Expression::kVariableReference_Kind: {
@@ -1771,7 +1771,7 @@ std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(Expres
     }
 }
 
-SpvId SPIRVCodeGenerator::writeVariableReference(VariableReference& ref, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, std::ostream& out) {
     auto entry = fVariableMap.find(&ref.fVariable);
     ASSERT(entry != fVariableMap.end());
     SpvId var = entry->second;
@@ -1780,15 +1780,15 @@ SpvId SPIRVCodeGenerator::writeVariableReference(VariableReference& ref, std::os
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeIndexExpression(IndexExpression& expr, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, std::ostream& out) {
     return getLValue(expr, out)->load(out);
 }
 
-SpvId SPIRVCodeGenerator::writeFieldAccess(FieldAccess& f, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, std::ostream& out) {
     return getLValue(f, out)->load(out);
 }
 
-SpvId SPIRVCodeGenerator::writeSwizzle(Swizzle& swizzle, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, std::ostream& out) {
     SpvId base = this->writeExpression(*swizzle.fBase, out);
     SpvId result = this->nextId();
     size_t count = swizzle.fComponents.size();
@@ -1849,7 +1849,7 @@ bool is_assignment(Token::Kind op) {
     }
 }
 
-SpvId SPIRVCodeGenerator::writeBinaryExpression(BinaryExpression& b, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std::ostream& out) {
     // handle cases where we don't necessarily evaluate both LHS and RHS
     switch (b.fOperator) {
         case Token::EQ: {
@@ -2041,7 +2041,7 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(BinaryExpression& b, std::ostrea
     }
 }
 
-SpvId SPIRVCodeGenerator::writeLogicalAnd(BinaryExpression& a, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, std::ostream& out) {
     ASSERT(a.fOperator == Token::LOGICALAND);
     BoolLiteral falseLiteral(fContext, Position(), false);
     SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
@@ -2062,7 +2062,7 @@ SpvId SPIRVCodeGenerator::writeLogicalAnd(BinaryExpression& a, std::ostream& out
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeLogicalOr(BinaryExpression& o, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, std::ostream& out) {
     ASSERT(o.fOperator == Token::LOGICALOR);
     BoolLiteral trueLiteral(fContext, Position(), true);
     SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
@@ -2083,7 +2083,7 @@ SpvId SPIRVCodeGenerator::writeLogicalOr(BinaryExpression& o, std::ostream& out)
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeTernaryExpression(TernaryExpression& t, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, std::ostream& out) {
     SpvId test = this->writeExpression(*t.fTest, out);
     if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
         // both true and false are constants, can just use OpSelect
@@ -2127,7 +2127,7 @@ std::unique_ptr<Expression> create_literal_1(const Context& context, const Type&
     }
 }
 
-SpvId SPIRVCodeGenerator::writePrefixExpression(PrefixExpression& p, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, std::ostream& out) {
     if (p.fOperator == Token::MINUS) {
         SpvId result = this->nextId();
         SpvId typeId = this->getType(p.fType);
@@ -2174,7 +2174,7 @@ SpvId SPIRVCodeGenerator::writePrefixExpression(PrefixExpression& p, std::ostrea
     }
 }
 
-SpvId SPIRVCodeGenerator::writePostfixExpression(PostfixExpression& p, std::ostream& out) {
+SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, std::ostream& out) {
     std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
     SpvId result = lv->load(out);
     SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
@@ -2196,7 +2196,7 @@ SpvId SPIRVCodeGenerator::writePostfixExpression(PostfixExpression& p, std::ostr
     }
 }
 
-SpvId SPIRVCodeGenerator::writeBoolLiteral(BoolLiteral& b) {
+SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
     if (b.fValue) {
         if (fBoolTrue == 0) {
             fBoolTrue = this->nextId();
@@ -2214,7 +2214,7 @@ SpvId SPIRVCodeGenerator::writeBoolLiteral(BoolLiteral& b) {
     }
 }
 
-SpvId SPIRVCodeGenerator::writeIntLiteral(IntLiteral& i) {
+SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
     if (i.fType == *fContext.fInt_Type) {
         auto entry = fIntConstants.find(i.fValue);
         if (entry == fIntConstants.end()) {
@@ -2239,7 +2239,7 @@ SpvId SPIRVCodeGenerator::writeIntLiteral(IntLiteral& i) {
     }
 }
 
-SpvId SPIRVCodeGenerator::writeFloatLiteral(FloatLiteral& f) {
+SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
     if (f.fType == *fContext.fFloat_Type) {
         float value = (float) f.fValue;
         auto entry = fFloatConstants.find(value);
@@ -2350,7 +2350,7 @@ void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int mem
     }
 }
 
-SpvId SPIRVCodeGenerator::writeInterfaceBlock(InterfaceBlock& intf) {
+SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
     SpvId type = this->getType(intf.fVariable.fType);
     SpvId result = this->nextId();
     this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
@@ -2363,7 +2363,7 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(InterfaceBlock& intf) {
     return result;
 }
 
-void SPIRVCodeGenerator::writeGlobalVars(VarDeclaration& decl, std::ostream& out) {
+void SPIRVCodeGenerator::writeGlobalVars(const VarDeclaration& decl, std::ostream& out) {
     for (size_t i = 0; i < decl.fVars.size(); i++) {
         if (!decl.fVars[i]->fIsReadFrom && !decl.fVars[i]->fIsWrittenTo &&
                 !(decl.fVars[i]->fModifiers.fFlags & (Modifiers::kIn_Flag |
@@ -2399,17 +2399,17 @@ void SPIRVCodeGenerator::writeGlobalVars(VarDeclaration& decl, std::ostream& out
                                    (SpvId) decl.fVars[i]->fType.stride(), fDecorationBuffer);
         }
         if (decl.fValues[i]) {
-                       ASSERT(!fCurrentBlock);
-                       fCurrentBlock = -1;
+            ASSERT(!fCurrentBlock);
+            fCurrentBlock = -1;
             SpvId value = this->writeExpression(*decl.fValues[i], fGlobalInitializersBuffer);
             this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
-                       fCurrentBlock = 0;
+            fCurrentBlock = 0;
         }
         this->writeLayout(decl.fVars[i]->fModifiers.fLayout, id);
     }
 }
 
-void SPIRVCodeGenerator::writeVarDeclaration(VarDeclaration& decl, std::ostream& out) {
+void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& decl, std::ostream& out) {
     for (size_t i = 0; i < decl.fVars.size(); i++) {
         SpvId id = this->nextId();
         fVariableMap[decl.fVars[i]] = id;
@@ -2423,7 +2423,7 @@ void SPIRVCodeGenerator::writeVarDeclaration(VarDeclaration& decl, std::ostream&
     }
 }
 
-void SPIRVCodeGenerator::writeStatement(Statement& s, std::ostream& out) {
+void SPIRVCodeGenerator::writeStatement(const Statement& s, std::ostream& out) {
     switch (s.fKind) {
         case Statement::kBlock_Kind:
             this->writeBlock((Block&) s, out);
@@ -2457,13 +2457,13 @@ void SPIRVCodeGenerator::writeStatement(Statement& s, std::ostream& out) {
     }
 }
 
-void SPIRVCodeGenerator::writeBlock(Block& b, std::ostream& out) {
+void SPIRVCodeGenerator::writeBlock(const Block& b, std::ostream& out) {
     for (size_t i = 0; i < b.fStatements.size(); i++) {
         this->writeStatement(*b.fStatements[i], out);
     }
 }
 
-void SPIRVCodeGenerator::writeIfStatement(IfStatement& stmt, std::ostream& out) {
+void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, std::ostream& out) {
     SpvId test = this->writeExpression(*stmt.fTest, out);
     SpvId ifTrue = this->nextId();
     SpvId ifFalse = this->nextId();
@@ -2494,7 +2494,7 @@ void SPIRVCodeGenerator::writeIfStatement(IfStatement& stmt, std::ostream& out)
     }
 }
 
-void SPIRVCodeGenerator::writeForStatement(ForStatement& f, std::ostream& out) {
+void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, std::ostream& out) {
     if (f.fInitializer) {
         this->writeStatement(*f.fInitializer, out);
     }
@@ -2508,7 +2508,7 @@ void SPIRVCodeGenerator::writeForStatement(ForStatement& f, std::ostream& out) {
     this->writeInstruction(SpvOpBranch, header, out);
     this->writeLabel(header, out);
     this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
-       this->writeInstruction(SpvOpBranch, start, out);
+    this->writeInstruction(SpvOpBranch, start, out);
     this->writeLabel(start, out);
     SpvId test = this->writeExpression(*f.fTest, out);
     this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
@@ -2527,7 +2527,7 @@ void SPIRVCodeGenerator::writeForStatement(ForStatement& f, std::ostream& out) {
     fContinueTarget.pop();
 }
 
-void SPIRVCodeGenerator::writeReturnStatement(ReturnStatement& r, std::ostream& out) {
+void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, std::ostream& out) {
     if (r.fExpression) {
         this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out), 
                                out);
@@ -2536,7 +2536,7 @@ void SPIRVCodeGenerator::writeReturnStatement(ReturnStatement& r, std::ostream&
     }
 }
 
-void SPIRVCodeGenerator::writeInstructions(Program& program, std::ostream& out) {
+void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& out) {
     fGLSLExtendedInstructions = this->nextId();
     std::stringstream body;
     std::vector<SpvId> interfaceVars;
@@ -2569,7 +2569,7 @@ void SPIRVCodeGenerator::writeInstructions(Program& program, std::ostream& out)
     }
     const FunctionDeclaration* main = nullptr;
     for (auto entry : fFunctionMap) {
-               if (entry.first->fName == "main") {
+        if (entry.first->fName == "main") {
             main = entry.first;
         }
     }
@@ -2621,7 +2621,7 @@ void SPIRVCodeGenerator::writeInstructions(Program& program, std::ostream& out)
     out << body.str();
 }
 
-void SPIRVCodeGenerator::generateCode(Program& program, std::ostream& out) {
+void SPIRVCodeGenerator::generateCode(const Program& program, std::ostream& out) {
     this->writeWord(SpvMagicNumber, out);
     this->writeWord(SpvVersion, out);
     this->writeWord(SKSL_MAGIC, out);
index a20ad9f..caae201 100644 (file)
@@ -71,7 +71,7 @@ public:
         this->setupIntrinsics();
     }
 
-    void generateCode(Program& program, std::ostream& out) override;
+    void generateCode(const Program& program, std::ostream& out) override;
 
 private:
     enum IntrinsicKind {
@@ -97,7 +97,7 @@ private:
 
     SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass);
 
-    std::vector<SpvId> getAccessChain(Expression& expr, std::ostream& out);
+    std::vector<SpvId> getAccessChain(const Expression& expr, std::ostream& out);
 
     void writeLayout(const Layout& layout, SpvId target);
 
@@ -105,9 +105,9 @@ private:
 
     void writeStruct(const Type& type, SpvId resultId);
 
-    void writeProgramElement(ProgramElement& pe, std::ostream& out);
+    void writeProgramElement(const ProgramElement& pe, std::ostream& out);
 
-    SpvId writeInterfaceBlock(InterfaceBlock& intf);
+    SpvId writeInterfaceBlock(const InterfaceBlock& intf);
 
     SpvId writeFunctionStart(const FunctionDeclaration& f, std::ostream& out);
     
@@ -115,78 +115,78 @@ private:
 
     SpvId writeFunction(const FunctionDefinition& f, std::ostream& out);
 
-    void writeGlobalVars(VarDeclaration& v, std::ostream& out);
+    void writeGlobalVars(const VarDeclaration& v, std::ostream& out);
 
-    void writeVarDeclaration(VarDeclaration& decl, std::ostream& out);
+    void writeVarDeclaration(const VarDeclaration& decl, std::ostream& out);
 
-    SpvId writeVariableReference(VariableReference& ref, std::ostream& out);
+    SpvId writeVariableReference(const VariableReference& ref, std::ostream& out);
 
-    std::unique_ptr<LValue> getLValue(Expression& value, std::ostream& out);
+    std::unique_ptr<LValue> getLValue(const Expression& value, std::ostream& out);
 
-    SpvId writeExpression(Expression& expr, std::ostream& out);
+    SpvId writeExpression(const Expression& expr, std::ostream& out);
     
-    SpvId writeIntrinsicCall(FunctionCall& c, std::ostream& out);
+    SpvId writeIntrinsicCall(const FunctionCall& c, std::ostream& out);
 
-    SpvId writeFunctionCall(FunctionCall& c, std::ostream& out);
+    SpvId writeFunctionCall(const FunctionCall& c, std::ostream& out);
 
-    SpvId writeSpecialIntrinsic(FunctionCall& c, SpecialIntrinsic kind, std::ostream& out);
+    SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, std::ostream& out);
 
-    SpvId writeConstantVector(Constructor& c);
+    SpvId writeConstantVector(const Constructor& c);
 
-    SpvId writeFloatConstructor(Constructor& c, std::ostream& out);
+    SpvId writeFloatConstructor(const Constructor& c, std::ostream& out);
 
-    SpvId writeIntConstructor(Constructor& c, std::ostream& out);
+    SpvId writeIntConstructor(const Constructor& c, std::ostream& out);
     
-    SpvId writeMatrixConstructor(Constructor& c, std::ostream& out);
+    SpvId writeMatrixConstructor(const Constructor& c, std::ostream& out);
 
-    SpvId writeVectorConstructor(Constructor& c, std::ostream& out);
+    SpvId writeVectorConstructor(const Constructor& c, std::ostream& out);
 
-    SpvId writeConstructor(Constructor& c, std::ostream& out);
+    SpvId writeConstructor(const Constructor& c, std::ostream& out);
 
-    SpvId writeFieldAccess(FieldAccess& f, std::ostream& out);
+    SpvId writeFieldAccess(const FieldAccess& f, std::ostream& out);
 
-    SpvId writeSwizzle(Swizzle& swizzle, std::ostream& out);
+    SpvId writeSwizzle(const Swizzle& swizzle, std::ostream& out);
 
     SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs, 
                                SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt, 
                                SpvOp_ ifBool, std::ostream& out);
 
-    SpvId writeBinaryOperation(BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
-                               std::ostream& out);
+    SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt, 
+                               SpvOp_ ifUInt, std::ostream& out);
 
-    SpvId writeBinaryExpression(BinaryExpression& b, std::ostream& out);
+    SpvId writeBinaryExpression(const BinaryExpression& b, std::ostream& out);
 
-    SpvId writeTernaryExpression(TernaryExpression& t, std::ostream& out);
+    SpvId writeTernaryExpression(const TernaryExpression& t, std::ostream& out);
 
-    SpvId writeIndexExpression(IndexExpression& expr, std::ostream& out);
+    SpvId writeIndexExpression(const IndexExpression& expr, std::ostream& out);
 
-    SpvId writeLogicalAnd(BinaryExpression& b, std::ostream& out);
+    SpvId writeLogicalAnd(const BinaryExpression& b, std::ostream& out);
 
-    SpvId writeLogicalOr(BinaryExpression& o, std::ostream& out);
+    SpvId writeLogicalOr(const BinaryExpression& o, std::ostream& out);
 
-    SpvId writePrefixExpression(PrefixExpression& p, std::ostream& out);
+    SpvId writePrefixExpression(const PrefixExpression& p, std::ostream& out);
 
-    SpvId writePostfixExpression(PostfixExpression& p, std::ostream& out);
+    SpvId writePostfixExpression(const PostfixExpression& p, std::ostream& out);
 
-    SpvId writeBoolLiteral(BoolLiteral& b);
+    SpvId writeBoolLiteral(const BoolLiteral& b);
 
-    SpvId writeIntLiteral(IntLiteral& i);
+    SpvId writeIntLiteral(const IntLiteral& i);
 
-    SpvId writeFloatLiteral(FloatLiteral& f);
+    SpvId writeFloatLiteral(const FloatLiteral& f);
 
-    void writeStatement(Statement& s, std::ostream& out);
+    void writeStatement(const Statement& s, std::ostream& out);
 
-    void writeBlock(Block& b, std::ostream& out);
+    void writeBlock(const Block& b, std::ostream& out);
 
-    void writeIfStatement(IfStatement& stmt, std::ostream& out);
+    void writeIfStatement(const IfStatement& stmt, std::ostream& out);
 
-    void writeForStatement(ForStatement& f, std::ostream& out);
+    void writeForStatement(const ForStatement& f, std::ostream& out);
 
-    void writeReturnStatement(ReturnStatement& r, std::ostream& out);
+    void writeReturnStatement(const ReturnStatement& r, std::ostream& out);
 
     void writeCapabilities(std::ostream& out);
 
-    void writeInstructions(Program& program, std::ostream& out);
+    void writeInstructions(const Program& program, std::ostream& out);
 
     void writeOpCode(SpvOp_ opCode, int length, std::ostream& out);
 
index 538ae50..29fa81e 100644 (file)
  
 namespace SkSL {
 
+#undef IN
+#undef OUT
+#undef CONST
+
 /**
  * Represents a lexical analysis token. Token is generally only used during the parse process, but
  * Token::Kind is also used to represent operator kinds.
@@ -89,6 +93,8 @@ struct Token {
         MEDIUMP,
         HIGHP,
         UNIFORM,
+        FLAT,
+        NOPERSPECTIVE,
         STRUCT,
         LAYOUT,
         DIRECTIVE,
index 5536d93..33611cd 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef SKSL_UTIL
 #define SKSL_UTIL
 
+#include <iomanip>
 #include <string>
 #include <sstream>
 #include "stdlib.h"
@@ -19,13 +20,9 @@ namespace SkSL {
 // our own definitions of certain std:: functions, because they are not always present on Android
 
 template <typename T> std::string to_string(T value) {
-#ifdef SK_BUILD_FOR_ANDROID
     std::stringstream buffer;
-    buffer << value;
+    buffer << std::setprecision(std::numeric_limits<T>::digits10) << value;
     return buffer.str();
-#else
-    return std::to_string(value);
-#endif
 }
 
 #if _MSC_VER
index 487e6e9..08d6753 100644 (file)
@@ -20,12 +20,13 @@ namespace SkSL {
  */
 struct ASTLayout : public ASTNode {
     // For all parameters, a -1 means no value
-    ASTLayout(int location, int binding, int index, int set, int builtin)
+    ASTLayout(int location, int binding, int index, int set, int builtin, bool originUpperLeft)
     : fLocation(location)
     , fBinding(binding)
     , fIndex(index)
     , fSet(set)
-    , fBuiltin(builtin) {}
+    , fBuiltin(builtin)
+    , fOriginUpperLeft(originUpperLeft) {}
 
     std::string description() const {
         std::string result;
@@ -50,6 +51,10 @@ struct ASTLayout : public ASTNode {
             result += separator + "builtin = " + to_string(fBuiltin);
             separator = ", ";
         }
+        if (fOriginUpperLeft) {
+            result += separator + "origin_upper_left";
+            separator = ", ";
+        }
         if (result.length() > 0) {
             result = "layout (" + result + ")";
         }
@@ -61,6 +66,7 @@ struct ASTLayout : public ASTNode {
     const int fIndex;
     const int fSet;
     const int fBuiltin;
+    const bool fOriginUpperLeft;
 };
 
 } // namespace
index 6ef29aa..61d2e9f 100644 (file)
@@ -18,14 +18,16 @@ namespace SkSL {
  */
 struct ASTModifiers : public ASTNode {
     enum Flag {
-        kNo_Flag      =  0,
-        kConst_Flag   =  1,
-        kIn_Flag      =  2,
-        kOut_Flag     =  4,
-        kLowp_Flag    =  8,
-        kMediump_Flag = 16,
-        kHighp_Flag   = 32,
-        kUniform_Flag = 64
+        kNo_Flag            =  0,
+        kConst_Flag         =  1,
+        kIn_Flag            =  2,
+        kOut_Flag           =  4,
+        kLowp_Flag          =  8,
+        kMediump_Flag       = 16,
+        kHighp_Flag         = 32,
+        kUniform_Flag       = 64,
+        kFlat_Flag          = 128,
+        kNoPerspective_Flag = 256
     };
 
     ASTModifiers(ASTLayout layout, int flags)
@@ -49,6 +51,12 @@ struct ASTModifiers : public ASTNode {
         if (fFlags & kHighp_Flag) {
             result += "highp ";
         }
+        if (fFlags & kFlat_Flag) {
+            result += "flat ";
+        }
+        if (fFlags & kNoPerspective_Flag) {
+            result += "noperspective ";
+        }
 
         if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) {
             result += "inout ";
index 26be769..4305011 100644 (file)
@@ -19,7 +19,7 @@ namespace SkSL {
  */
 struct ASTNode {
     virtual ~ASTNode() {}
-       
+     
     virtual std::string description() const = 0;
 };
 
index 8f55a69..ba054e4 100644 (file)
@@ -26,7 +26,7 @@ struct BoolLiteral : public Expression {
     }
 
     bool isConstant() const override {
-       return true;
+        return true;
     }
 
     const bool fValue;
index f09c3a3..bcdd7ee 100644 (file)
@@ -17,10 +17,19 @@ namespace SkSL {
  * An expression which extracts a field from a struct, as in 'foo.bar'.
  */
 struct FieldAccess : public Expression {
-    FieldAccess(std::unique_ptr<Expression> base, int fieldIndex)
+    enum OwnerKind {
+        kDefault_OwnerKind,
+        // this field access is to a field of an anonymous interface block (and thus, the field name
+        // is actually in global scope, so only the field name needs to be written in GLSL)
+        kAnonymousInterfaceBlock_OwnerKind
+    };
+
+    FieldAccess(std::unique_ptr<Expression> base, int fieldIndex, 
+                OwnerKind ownerKind = kDefault_OwnerKind)
     : INHERITED(base->fPosition, kFieldAccess_Kind, base->fType.fields()[fieldIndex].fType)
     , fBase(std::move(base))
-    , fFieldIndex(fieldIndex) {}
+    , fFieldIndex(fieldIndex)
+    , fOwnerKind(ownerKind) {}
 
     virtual std::string description() const override {
         return fBase->description() + "." + fBase->fType.fields()[fFieldIndex].fName;
@@ -28,6 +37,7 @@ struct FieldAccess : public Expression {
 
     const std::unique_ptr<Expression> fBase;
     const int fFieldIndex;
+    const OwnerKind fOwnerKind;
 
     typedef Expression INHERITED;
 };
index d9c8b65..a8fcfcf 100644 (file)
@@ -26,7 +26,7 @@ struct FloatLiteral : public Expression {
     }
 
     bool isConstant() const override {
-       return true;
+        return true;
     }
 
     const double fValue;
index 5d97a58..f3f8fb7 100644 (file)
@@ -24,8 +24,8 @@ struct FunctionReference : public Expression {
     , fFunctions(function) {}
 
     virtual std::string description() const override {
-       ASSERT(false);
-       return "<function>";
+        ASSERT(false);
+        return "<function>";
     }
 
     const std::vector<const FunctionDeclaration*> fFunctions;
index f2bf40b..2bc5657 100644 (file)
@@ -27,7 +27,7 @@ struct IntLiteral : public Expression {
     }
 
    bool isConstant() const override {
-       return true;
+        return true;
     }
 
     const int64_t fValue;
index bab2f0e..d8dc980 100644 (file)
@@ -21,14 +21,16 @@ struct Layout {
     , fBinding(layout.fBinding)
     , fIndex(layout.fIndex)
     , fSet(layout.fSet)
-    , fBuiltin(layout.fBuiltin) {}
+    , fBuiltin(layout.fBuiltin)
+    , fOriginUpperLeft(layout.fOriginUpperLeft) {}
 
-    Layout(int location, int binding, int index, int set, int builtin)
+    Layout(int location, int binding, int index, int set, int builtin, bool originUpperLeft)
     : fLocation(location)
     , fBinding(binding)
     , fIndex(index)
     , fSet(set)
-    , fBuiltin(builtin) {}
+    , fBuiltin(builtin)
+    , fOriginUpperLeft(originUpperLeft) {}
 
     std::string description() const {
         std::string result;
@@ -53,6 +55,10 @@ struct Layout {
             result += separator + "builtin = " + to_string(fBuiltin);
             separator = ", ";
         }
+        if (fOriginUpperLeft) {
+            result += separator + "origin_upper_left";
+            separator = ", ";
+        }
         if (result.length() > 0) {
             result = "layout (" + result + ")";
         }
@@ -71,11 +77,14 @@ struct Layout {
         return !(*this == other);
     }
 
-    const int fLocation;
-    const int fBinding;
-    const int fIndex;
-    const int fSet;
-    const int fBuiltin;
+    // everything but builtin is in the GLSL spec; builtin comes from SPIR-V and identifies which
+    // particular builtin value this object represents.
+    int fLocation;
+    int fBinding;
+    int fIndex;
+    int fSet;
+    int fBuiltin;
+    bool fOriginUpperLeft;
 };
 
 } // namespace
index d3b9c40..f39e929 100644 (file)
@@ -18,14 +18,16 @@ namespace SkSL {
  */
 struct Modifiers {
     enum Flag {
-        kNo_Flag      = ASTModifiers::kNo_Flag,
-        kConst_Flag   = ASTModifiers::kConst_Flag,
-        kIn_Flag      = ASTModifiers::kIn_Flag,
-        kOut_Flag     = ASTModifiers::kOut_Flag,
-        kLowp_Flag    = ASTModifiers::kLowp_Flag,
-        kMediump_Flag = ASTModifiers::kMediump_Flag,
-        kHighp_Flag   = ASTModifiers::kHighp_Flag,
-        kUniform_Flag = ASTModifiers::kUniform_Flag
+        kNo_Flag            = ASTModifiers::kNo_Flag,
+        kConst_Flag         = ASTModifiers::kConst_Flag,
+        kIn_Flag            = ASTModifiers::kIn_Flag,
+        kOut_Flag           = ASTModifiers::kOut_Flag,
+        kLowp_Flag          = ASTModifiers::kLowp_Flag,
+        kMediump_Flag       = ASTModifiers::kMediump_Flag,
+        kHighp_Flag         = ASTModifiers::kHighp_Flag,
+        kUniform_Flag       = ASTModifiers::kUniform_Flag,
+        kFlat_Flag          = ASTModifiers::kFlat_Flag,
+        kNoPerspective_Flag = ASTModifiers::kNoPerspective_Flag
     };
 
     Modifiers(const ASTModifiers& modifiers)
@@ -53,6 +55,12 @@ struct Modifiers {
         if (fFlags & kHighp_Flag) {
             result += "highp ";
         }
+        if (fFlags & kFlat_Flag) {
+            result += "flat ";
+        }
+        if (fFlags & kNoPerspective_Flag) {
+            result += "noperspective ";
+        }
 
         if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) {
             result += "inout ";
@@ -73,8 +81,8 @@ struct Modifiers {
         return !(*this == other);
     }
 
-    const Layout fLayout;
-    const int fFlags;
+    Layout fLayout;
+    int fFlags;
 };
 
 } // namespace
index 76923aa..10f36aa 100644 (file)
@@ -23,8 +23,8 @@ struct TypeReference : public Expression {
     , fValue(type) {}
 
     std::string description() const override {
-       ASSERT(false);
-       return "<type>";
+        ASSERT(false);
+        return "<type>";
     }
 
     const Type& fValue;
index 3a368ad..7e8a360 100644 (file)
@@ -20,9 +20,9 @@ struct UnresolvedFunction : public Symbol {
     : INHERITED(Position(), kUnresolvedFunction_Kind, funcs[0]->fName)
     , fFunctions(std::move(funcs)) {
 #ifdef DEBUG
-       for (auto func : funcs) {
-               ASSERT(func->fName == fName);
-       }
+        for (auto func : funcs) {
+            ASSERT(func->fName == fName);
+        }
 #endif
     }
 
index b234231..ca3c7f9 100644 (file)
@@ -16,14 +16,15 @@ namespace SkSL {
 
 /**
  * A variable declaration, which may consist of multiple individual variables. For instance
- * 'int x, y = 1, z[4][2];' is a single VarDeclaration. This declaration would have a type of 'int', 
- * names ['x', 'y', 'z'], sizes of [[], [], [4, 2]], and values of [null, 1, null].
+ * 'int x, y = 1, z[4][2];' is a single VarDeclaration. This declaration would have a base type of 
+ * 'int', names ['x', 'y', 'z'], sizes of [[], [], [4, 2]], and values of [null, 1, null].
  */
 struct VarDeclaration : public ProgramElement {
-    VarDeclaration(Position position, std::vector<const Variable*> vars,
+    VarDeclaration(Position position, const Type* baseType, std::vector<const Variable*> vars,
                    std::vector<std::vector<std::unique_ptr<Expression>>> sizes,
                    std::vector<std::unique_ptr<Expression>> values)
-    : INHERITED(position, kVar_Kind) 
+    : INHERITED(position, kVar_Kind)
+    , fBaseType(*baseType)
     , fVars(std::move(vars))
     , fSizes(std::move(sizes))
     , fValues(std::move(values)) {}
@@ -55,6 +56,7 @@ struct VarDeclaration : public ProgramElement {
         return result;
     }
 
+    const Type& fBaseType;
     const std::vector<const Variable*> fVars;
     const std::vector<std::vector<std::unique_ptr<Expression>>> fSizes;
     const std::vector<std::unique_ptr<Expression>> fValues;
index 39af309..217b100 100644 (file)
@@ -40,7 +40,7 @@ struct Variable : public Symbol {
         return fModifiers.description() + fType.fName + " " + fName;
     }
 
-    const Modifiers fModifiers;
+    mutable Modifiers fModifiers;
     const Type& fType;
     const Storage fStorage;
 
index 7afbd94..4993fac 100644 (file)
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+
 #line 3 "lex.sksl.c"
 
 #define  YY_INT_ALIGNED short int
@@ -14,7 +14,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_SUBMINOR_VERSION 37
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -52,7 +52,6 @@ typedef int16_t flex_int16_t;
 typedef uint16_t flex_uint16_t;
 typedef int32_t flex_int32_t;
 typedef uint32_t flex_uint32_t;
-typedef uint64_t flex_uint64_t;
 #else
 typedef signed char flex_int8_t;
 typedef short int flex_int16_t;
@@ -60,7 +59,6 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 /* Limits of integral types. */
 #ifndef INT8_MIN
@@ -91,6 +89,8 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#endif /* ! C99 */
+
 #endif /* ! FLEXINT_H */
 
 #ifdef __cplusplus
@@ -194,7 +194,7 @@ typedef size_t yy_size_t;
      */
     #define  YY_LESS_LINENO(n) \
             do { \
-                yy_size_t yyl;\
+                int yyl;\
                 for ( yyl = n; yyl < yyleng; ++yyl )\
                     if ( yytext[yyl] == '\n' )\
                         --yylineno;\
@@ -360,13 +360,13 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
  */
 #define YY_DO_BEFORE_ACTION \
        yyg->yytext_ptr = yy_bp; \
-       yyleng = (yy_size_t) (yy_cp - yy_bp); \
+       yyleng = (size_t) (yy_cp - yy_bp); \
        yyg->yy_hold_char = *yy_cp; \
        *yy_cp = '\0'; \
        yyg->yy_c_buf_p = yy_cp;
 
-#define YY_NUM_RULES 80
-#define YY_END_OF_BUFFER 81
+#define YY_NUM_RULES 82
+#define YY_END_OF_BUFFER 83
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -374,28 +374,30 @@ struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
-static yyconst flex_int16_t yy_accept[185] =
+static yyconst flex_int16_t yy_accept[201] =
     {   0,
-        0,    0,   81,   79,   78,   78,   52,   79,   27,   43,
-       48,   29,   30,   41,   39,   36,   40,   35,   42,    4,
-       54,   75,   59,   55,   58,   53,   33,   34,   47,   27,
-       27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
-       27,   27,   27,   27,   27,   31,   46,   32,   78,   57,
-       28,   27,   66,   51,   71,   64,   37,   62,   38,   63,
-        1,    0,   76,   65,    2,    4,    0,   44,   61,   56,
-       60,   45,   70,   50,   27,   27,   27,   11,   27,   27,
-       27,   27,    7,   16,   27,   27,   27,   27,   27,   27,
-       27,   27,   27,   27,   69,   49,   28,   74,    0,    0,
-
-        0,   76,    1,    0,    0,    3,   67,   68,   73,   27,
-       27,   27,   27,   27,    9,   27,   27,   27,   27,   27,
-       17,   27,   27,   27,   27,   27,   27,   72,    0,    1,
-       77,    0,    0,    2,   27,   27,   27,   27,    8,   27,
-       27,   27,   27,   21,   27,   27,   27,   27,    5,   27,
-       27,    0,    1,   12,   20,   27,   27,    6,   23,   18,
-       27,   27,   27,   27,   27,   27,   10,   27,   27,   25,
-       27,   27,   15,   24,   27,   27,   14,   22,   27,   19,
-       13,   27,   26,    0
+        0,    0,   83,   81,   80,   80,   54,   81,   29,   45,
+       50,   31,   32,   43,   41,   38,   42,   37,   44,    4,
+       56,   77,   61,   57,   60,   55,   35,   36,   49,   29,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   33,   48,   34,   80,
+       59,   30,   29,   68,   53,   73,   66,   39,   64,   40,
+       65,    1,    0,   78,   67,    2,    4,    0,   46,   63,
+       58,   62,   47,   72,   52,   29,   29,   29,   11,   29,
+       29,   29,   29,   29,    7,   16,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   29,   71,   51,   30,
+
+       76,    0,    0,    0,   78,    1,    0,    0,    3,   69,
+       70,   75,   29,   29,   29,   29,   29,   29,    9,   29,
+       29,   29,   29,   29,   29,   17,   29,   29,   29,   29,
+       29,   29,   74,    0,    1,   79,    0,    0,    2,   29,
+       29,   29,   29,    8,   29,   24,   29,   29,   29,   21,
+       29,   29,   29,   29,   29,    5,   29,   29,    0,    1,
+       12,   20,   29,   29,    6,   23,   18,   29,   29,   29,
+       29,   29,   29,   29,   10,   29,   29,   27,   29,   29,
+       29,   15,   26,   29,   29,   14,   22,   29,   29,   19,
+       13,   29,   29,   29,   28,   29,   29,   29,   25,    0
+
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -412,8 +414,8 @@ static yyconst flex_int32_t yy_ec[256] =
        25,    1,   26,   27,    6,    1,   28,   29,   30,   31,
 
        32,   33,   34,   35,   36,    6,   37,   38,   39,   40,
-       41,   42,    6,   43,   44,   45,   46,    6,   47,    6,
-       48,    6,   49,   50,   51,    1,    1,    1,    1,    1,
+       41,   42,    6,   43,   44,   45,   46,   47,   48,    6,
+       49,    6,   50,   51,   52,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -430,140 +432,152 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[52] =
+static yyconst flex_int32_t yy_meta[53] =
     {   0,
         1,    1,    2,    1,    1,    3,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    4,    1,    1,    1,
         1,    1,    1,    3,    1,    1,    1,    3,    3,    3,
         3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    3,    3,    3,    3,    3,    3,    1,    1,
-        1
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    1,
+        1,    1
     } ;
 
-static yyconst flex_int16_t yy_base[190] =
+static yyconst flex_int16_t yy_base[206] =
     {   0,
-        0,    0,  222,  223,   50,   52,  200,    0,    0,  199,
-       48,  223,  223,  198,   45,  223,   44,  201,   51,   44,
-      223,  223,   43,  196,   49,  223,  223,  223,   52,  173,
-      174,   39,  176,   46,  177,   44,   50,  180,  165,  167,
-      177,  163,  164,  166,  170,  223,   39,  223,   79,  223,
-        0,    0,  223,  183,  223,  223,  223,  223,  223,  223,
-       66,  192,    0,  223,   68,   71,   82,  181,  223,  223,
-      223,  180,  223,  179,  167,  158,  153,    0,  152,  157,
-      151,  159,    0,  151,  143,  143,  158,  143,  155,  141,
-      142,  138,  147,  146,  223,  160,    0,  223,   90,  169,
-
-      163,    0,   84,   97,  161,  160,  223,  223,  223,  148,
-       61,  145,  142,  129,    0,  137,  125,  129,  127,  132,
-        0,  137,  120,  119,  132,  130,  124,  223,  144,  143,
-      223,   98,  142,  141,  120,  111,  119,  126,    0,  121,
-      110,  106,  104,    0,  103,  112,  104,  116,    0,  104,
-      112,  126,  125,    0,    0,  101,   97,    0,    0,    0,
-       94,   99,   93,   96,   90,   91,    0,   87,  101,    0,
-       89,   94,    0,    0,   90,   94,    0,    0,   72,    0,
-        0,   57,    0,  223,   90,  114,  116,  120,  124
+        0,    0,  238,  239,   51,   53,  216,    0,    0,  215,
+       49,  239,  239,  214,   46,  239,   45,  217,   52,   45,
+      239,  239,   44,  212,   50,  239,  239,  239,   53,  189,
+      190,   40,  192,   47,  193,   46,   50,  196,  186,  180,
+      182,  192,  178,  179,  181,  185,  239,   61,  239,   81,
+      239,    0,    0,  239,  198,  239,  239,  239,  239,  239,
+      239,   70,  207,    0,  239,   72,   75,   81,  196,  239,
+      239,  239,  195,  239,  194,  182,  173,  168,    0,  167,
+      172,  181,  165,  173,    0,  165,  156,  156,  172,  160,
+      156,  168,  154,  155,  151,  160,  159,  239,  173,    0,
+
+      239,   89,  182,  176,    0,   91,   97,  174,  173,  239,
+      239,  239,  161,   72,  158,  155,  142,  140,    0,  149,
+      137,  141,  139,  144,  147,    0,  148,  131,  130,  143,
+      141,  135,  239,  155,  154,  239,  107,  153,  152,  131,
+      122,  130,  137,    0,  132,    0,  121,  117,  115,    0,
+      114,  116,  122,  114,  126,    0,  114,  122,  136,  135,
+        0,    0,  111,  107,    0,    0,    0,  104,  109,  103,
+      102,  105,   99,  100,    0,   96,  110,    0,   98,   97,
+      102,    0,    0,   98,  102,    0,    0,   90,   79,    0,
+        0,   88,   73,   65,    0,   69,   53,   65,    0,  239,
+
+       58,  122,  124,  128,  132
     } ;
 
-static yyconst flex_int16_t yy_def[190] =
+static yyconst flex_int16_t yy_def[206] =
     {   0,
-      184,    1,  184,  184,  184,  184,  184,  185,  186,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  186,
-      186,  186,  186,  186,  186,  186,  186,  186,  186,  186,
-      186,  186,  186,  186,  186,  184,  184,  184,  184,  184,
-      187,  186,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  188,  189,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  186,  186,  186,  186,  186,  186,
-      186,  186,  186,  186,  186,  186,  186,  186,  186,  186,
-      186,  186,  186,  186,  184,  184,  187,  184,  184,  188,
-
-      188,  189,  184,  184,  184,  184,  184,  184,  184,  186,
-      186,  186,  186,  186,  186,  186,  186,  186,  186,  186,
-      186,  186,  186,  186,  186,  186,  186,  184,  184,  184,
-      184,  184,  184,  184,  186,  186,  186,  186,  186,  186,
-      186,  186,  186,  186,  186,  186,  186,  186,  186,  186,
-      186,  184,  184,  186,  186,  186,  186,  186,  186,  186,
-      186,  186,  186,  186,  186,  186,  186,  186,  186,  186,
-      186,  186,  186,  186,  186,  186,  186,  186,  186,  186,
-      186,  186,  186,    0,  184,  184,  184,  184,  184
+      200,    1,  200,  200,  200,  200,  200,  201,  202,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  200,  200,  200,  200,
+      200,  203,  202,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  204,  205,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  200,  200,  203,
+
+      200,  200,  204,  204,  205,  200,  200,  200,  200,  200,
+      200,  200,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  200,  200,  200,  200,  200,  200,  200,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  200,  200,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,    0,
+
+      200,  200,  200,  200,  200
     } ;
 
-static yyconst flex_int16_t yy_nxt[275] =
+static yyconst flex_int16_t yy_nxt[292] =
     {   0,
         4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
        14,   15,   16,   17,   18,   19,   20,   21,   22,   23,
        24,   25,   26,    9,   27,   28,   29,    9,   30,   31,
-       32,   33,   34,    9,   35,   36,    9,   37,   38,    9,
-       39,   40,   41,   42,   43,   44,   45,    9,   46,   47,
-       48,   49,   49,   49,   49,   54,   57,   59,   65,   95,
-       66,   62,   68,   69,   60,   58,   63,   67,   55,   71,
-       72,   64,   73,   80,   77,   67,   83,   85,   74,   78,
-       49,   49,   61,   84,  103,   65,   81,   66,   96,   99,
-       86,  104,   51,  105,   67,  105,  183,   99,  106,  104,
-
-      103,  129,   67,  129,  136,  137,  130,  132,  133,  152,
-      133,  152,  182,  134,  153,  132,   52,   52,   97,   97,
-      100,  100,  100,  100,  102,  181,  102,  102,  180,  179,
-      178,  177,  176,  175,  174,  173,  172,  171,  170,  169,
-      168,  153,  153,  167,  166,  165,  164,  163,  162,  161,
-      160,  159,  158,  157,  156,  155,  154,  134,  134,  130,
-      130,  151,  150,  149,  148,  147,  146,  145,  144,  143,
-      142,  141,  140,  139,  138,  135,  106,  106,  131,  101,
-      128,  127,  126,  125,  124,  123,  122,  121,  120,  119,
-      118,  117,  116,  115,  114,  113,  112,  111,  110,  109,
-
-      108,  107,  101,   98,   94,   93,   92,   91,   90,   89,
-       88,   87,   82,   79,   76,   75,   70,   61,   56,   53,
-       50,  184,    3,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184
+       32,   33,   34,    9,   35,   36,    9,   37,   38,   39,
+       40,   41,   42,   43,   44,   45,    9,   46,    9,   47,
+       48,   49,   50,   50,   50,   50,   55,   58,   60,   66,
+       52,   67,   63,   69,   70,   61,   59,   64,   68,   56,
+       72,   73,   65,   74,   81,   78,   68,   87,   85,   75,
+       79,   98,   50,   50,   82,   86,   62,   83,  106,   66,
+       88,   67,  108,  102,  108,  107,  199,  109,   68,  198,
+
+      134,  102,  134,  107,  197,  135,   68,  106,  138,  196,
+      138,   99,  195,  139,  137,  141,  142,  194,  159,  193,
+      159,  192,  137,  160,   53,   53,  100,  100,  103,  103,
+      103,  103,  105,  191,  105,  105,  190,  189,  188,  187,
+      186,  185,  184,  183,  182,  181,  180,  179,  178,  177,
+      176,  160,  160,  175,  174,  173,  172,  171,  170,  169,
+      168,  167,  166,  165,  164,  163,  162,  161,  139,  139,
+      135,  135,  158,  157,  156,  155,  154,  153,  152,  151,
+      150,  149,  148,  147,  146,  145,  144,  143,  140,  109,
+      109,  136,  104,  133,  132,  131,  130,  129,  128,  127,
+
+      126,  125,  124,  123,  122,  121,  120,  119,  118,  117,
+      116,  115,  114,  113,  112,  111,  110,  104,  101,   97,
+       96,   95,   94,   93,   92,   91,   90,   89,   84,   80,
+       77,   76,   71,   62,   57,   54,   51,  200,    3,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200
+
     } ;
 
-static yyconst flex_int16_t yy_chk[275] =
+static yyconst flex_int16_t yy_chk[292] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    5,    5,    6,    6,   11,   15,   17,   20,   47,
-       20,   19,   23,   23,   17,   15,   19,   20,   11,   25,
-       25,   19,   29,   34,   32,   20,   36,   37,   29,   32,
-       49,   49,   61,   36,   65,   66,   34,   66,   47,   61,
-       37,   65,  185,   67,   66,   67,  182,   61,   67,   65,
-
-      103,   99,   66,   99,  111,  111,   99,  103,  104,  132,
-      104,  132,  179,  104,  132,  103,  186,  186,  187,  187,
-      188,  188,  188,  188,  189,  176,  189,  189,  175,  172,
-      171,  169,  168,  166,  165,  164,  163,  162,  161,  157,
-      156,  153,  152,  151,  150,  148,  147,  146,  145,  143,
-      142,  141,  140,  138,  137,  136,  135,  134,  133,  130,
-      129,  127,  126,  125,  124,  123,  122,  120,  119,  118,
-      117,  116,  114,  113,  112,  110,  106,  105,  101,  100,
-       96,   94,   93,   92,   91,   90,   89,   88,   87,   86,
-       85,   84,   82,   81,   80,   79,   77,   76,   75,   74,
-
-       72,   68,   62,   54,   45,   44,   43,   42,   41,   40,
-       39,   38,   35,   33,   31,   30,   24,   18,   14,   10,
-        7,    3,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184,  184,  184,  184,  184,  184,  184,
-      184,  184,  184,  184
+        1,    1,    5,    5,    6,    6,   11,   15,   17,   20,
+      201,   20,   19,   23,   23,   17,   15,   19,   20,   11,
+       25,   25,   19,   29,   34,   32,   20,   37,   36,   29,
+       32,   48,   50,   50,   34,   36,   62,   34,   66,   67,
+       37,   67,   68,   62,   68,   66,  198,   68,   67,  197,
+
+      102,   62,  102,   66,  196,  102,   67,  106,  107,  194,
+      107,   48,  193,  107,  106,  114,  114,  192,  137,  189,
+      137,  188,  106,  137,  202,  202,  203,  203,  204,  204,
+      204,  204,  205,  185,  205,  205,  184,  181,  180,  179,
+      177,  176,  174,  173,  172,  171,  170,  169,  168,  164,
+      163,  160,  159,  158,  157,  155,  154,  153,  152,  151,
+      149,  148,  147,  145,  143,  142,  141,  140,  139,  138,
+      135,  134,  132,  131,  130,  129,  128,  127,  125,  124,
+      123,  122,  121,  120,  118,  117,  116,  115,  113,  109,
+      108,  104,  103,   99,   97,   96,   95,   94,   93,   92,
+
+       91,   90,   89,   88,   87,   86,   84,   83,   82,   81,
+       80,   78,   77,   76,   75,   73,   69,   63,   55,   46,
+       45,   44,   43,   42,   41,   40,   39,   38,   35,   33,
+       31,   30,   24,   18,   14,   10,    7,    3,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200
+
     } ;
 
 /* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[81] =
+static yyconst flex_int32_t yy_rule_can_match_eol[83] =
     {   0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0
-    0,     };
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+    1, 0, 0,     };
 
 /* The intent behind this definition is that it'll catch
  * any uses of REJECT which flex missed.
@@ -582,9 +596,11 @@ static yyconst flex_int32_t yy_rule_can_match_eol[81] =
 
                flex sksl.flex
 
+    You will have to manually add a copyright notice to the top of lex.sksl.c.
+    
 */
 #define YY_NO_UNISTD_H 1
-#line 582 "lex.sksl.c"
+#line 598 "lex.sksl.c"
 
 #define INITIAL 0
 
@@ -669,6 +685,10 @@ int skslget_lineno (yyscan_t yyscanner );
 
 void skslset_lineno (int line_number ,yyscan_t yyscanner );
 
+int skslget_column  (yyscan_t yyscanner );
+
+void skslset_column (int column_no ,yyscan_t yyscanner );
+
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
  */
@@ -711,7 +731,7 @@ static int input (yyscan_t yyscanner );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
 #endif
 
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
@@ -722,7 +742,7 @@ static int input (yyscan_t yyscanner );
        if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
                { \
                int c = '*'; \
-               yy_size_t n; \
+               size_t n; \
                for ( n = 0; n < max_size && \
                             (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
                        buf[n] = (char) c; \
@@ -805,10 +825,10 @@ YY_DECL
        register int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 21 "sksl.flex"
+#line 23 "sksl.flex"
 
 
-#line 806 "lex.sksl.c"
+#line 826 "lex.sksl.c"
 
        if ( !yyg->yy_init )
                {
@@ -861,13 +881,13 @@ yy_match:
                        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                                {
                                yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 185 )
+                               if ( yy_current_state >= 201 )
                                        yy_c = yy_meta[(unsigned int) yy_c];
                                }
                        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
                        ++yy_cp;
                        }
-               while ( yy_current_state != 184 );
+               while ( yy_current_state != 200 );
                yy_cp = yyg->yy_last_accepting_cpos;
                yy_current_state = yyg->yy_last_accepting_state;
 
@@ -878,7 +898,7 @@ yy_find_action:
 
                if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
                        {
-                       yy_size_t yyl;
+                       int yyl;
                        for ( yyl = 0; yyl < yyleng; ++yyl )
                                if ( yytext[yyl] == '\n' )
                                           
@@ -901,407 +921,417 @@ do_action:      /* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 23 "sksl.flex"
+#line 25 "sksl.flex"
 { return SkSL::Token::FLOAT_LITERAL; }
        YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 25 "sksl.flex"
+#line 27 "sksl.flex"
 { return SkSL::Token::FLOAT_LITERAL; }
        YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 27 "sksl.flex"
+#line 29 "sksl.flex"
 { return SkSL::Token::FLOAT_LITERAL; }
        YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 29 "sksl.flex"
+#line 31 "sksl.flex"
 { return SkSL::Token::INT_LITERAL; }
        YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 31 "sksl.flex"
+#line 33 "sksl.flex"
 { return SkSL::Token::TRUE_LITERAL; }
        YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 33 "sksl.flex"
+#line 35 "sksl.flex"
 { return SkSL::Token::FALSE_LITERAL; }
        YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 35 "sksl.flex"
+#line 37 "sksl.flex"
 { return SkSL::Token::IF; }
        YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 37 "sksl.flex"
+#line 39 "sksl.flex"
 { return SkSL::Token::ELSE; }
        YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 39 "sksl.flex"
+#line 41 "sksl.flex"
 { return SkSL::Token::FOR; }
        YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 41 "sksl.flex"
+#line 43 "sksl.flex"
 { return SkSL::Token::WHILE; }
        YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 43 "sksl.flex"
+#line 45 "sksl.flex"
 { return SkSL::Token::DO; }
        YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 45 "sksl.flex"
+#line 47 "sksl.flex"
 { return SkSL::Token::BREAK; }
        YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 47 "sksl.flex"
+#line 49 "sksl.flex"
 { return SkSL::Token::CONTINUE; }
        YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 49 "sksl.flex"
+#line 51 "sksl.flex"
 { return SkSL::Token::DISCARD; }
        YY_BREAK
 case 15:
 YY_RULE_SETUP
-#line 51 "sksl.flex"
+#line 53 "sksl.flex"
 { return SkSL::Token::RETURN; }
        YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 53 "sksl.flex"
+#line 55 "sksl.flex"
 { return SkSL::Token::IN; }
        YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 55 "sksl.flex"
+#line 57 "sksl.flex"
 { return SkSL::Token::OUT; }
        YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 57 "sksl.flex"
+#line 59 "sksl.flex"
 { return SkSL::Token::INOUT; }
        YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 59 "sksl.flex"
+#line 61 "sksl.flex"
 { return SkSL::Token::UNIFORM; }
        YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 61 "sksl.flex"
+#line 63 "sksl.flex"
 { return SkSL::Token::CONST; }
        YY_BREAK
 case 21:
 YY_RULE_SETUP
-#line 63 "sksl.flex"
+#line 65 "sksl.flex"
 { return SkSL::Token::LOWP; }
        YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 65 "sksl.flex"
+#line 67 "sksl.flex"
 { return SkSL::Token::MEDIUMP; }
        YY_BREAK
 case 23:
 YY_RULE_SETUP
-#line 67 "sksl.flex"
+#line 69 "sksl.flex"
 { return SkSL::Token::HIGHP; }
        YY_BREAK
 case 24:
 YY_RULE_SETUP
-#line 69 "sksl.flex"
-{ return SkSL::Token::STRUCT; }
+#line 71 "sksl.flex"
+{ return SkSL::Token::FLAT; }
        YY_BREAK
 case 25:
 YY_RULE_SETUP
-#line 71 "sksl.flex"
-{ return SkSL::Token::LAYOUT; }
+#line 73 "sksl.flex"
+{ return SkSL::Token::NOPERSPECTIVE; }
        YY_BREAK
 case 26:
 YY_RULE_SETUP
-#line 73 "sksl.flex"
-{ return SkSL::Token::PRECISION; }
+#line 75 "sksl.flex"
+{ return SkSL::Token::STRUCT; }
        YY_BREAK
 case 27:
 YY_RULE_SETUP
-#line 75 "sksl.flex"
-{ return SkSL::Token::IDENTIFIER; }
+#line 77 "sksl.flex"
+{ return SkSL::Token::LAYOUT; }
        YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 77 "sksl.flex"
-{ return SkSL::Token::DIRECTIVE; }
+#line 79 "sksl.flex"
+{ return SkSL::Token::PRECISION; }
        YY_BREAK
 case 29:
 YY_RULE_SETUP
-#line 79 "sksl.flex"
-{ return SkSL::Token::LPAREN; }
+#line 81 "sksl.flex"
+{ return SkSL::Token::IDENTIFIER; }
        YY_BREAK
 case 30:
 YY_RULE_SETUP
-#line 81 "sksl.flex"
-{ return SkSL::Token::RPAREN; }
+#line 83 "sksl.flex"
+{ return SkSL::Token::DIRECTIVE; }
        YY_BREAK
 case 31:
 YY_RULE_SETUP
-#line 83 "sksl.flex"
-{ return SkSL::Token::LBRACE; }
+#line 85 "sksl.flex"
+{ return SkSL::Token::LPAREN; }
        YY_BREAK
 case 32:
 YY_RULE_SETUP
-#line 85 "sksl.flex"
-{ return SkSL::Token::RBRACE; }
+#line 87 "sksl.flex"
+{ return SkSL::Token::RPAREN; }
        YY_BREAK
 case 33:
 YY_RULE_SETUP
-#line 87 "sksl.flex"
-{ return SkSL::Token::LBRACKET; }
+#line 89 "sksl.flex"
+{ return SkSL::Token::LBRACE; }
        YY_BREAK
 case 34:
 YY_RULE_SETUP
-#line 89 "sksl.flex"
-{ return SkSL::Token::RBRACKET; }
+#line 91 "sksl.flex"
+{ return SkSL::Token::RBRACE; }
        YY_BREAK
 case 35:
 YY_RULE_SETUP
-#line 91 "sksl.flex"
-{ return SkSL::Token::DOT; }
+#line 93 "sksl.flex"
+{ return SkSL::Token::LBRACKET; }
        YY_BREAK
 case 36:
 YY_RULE_SETUP
-#line 93 "sksl.flex"
-{ return SkSL::Token::COMMA; }
+#line 95 "sksl.flex"
+{ return SkSL::Token::RBRACKET; }
        YY_BREAK
 case 37:
 YY_RULE_SETUP
-#line 95 "sksl.flex"
-{ return SkSL::Token::PLUSPLUS; }
+#line 97 "sksl.flex"
+{ return SkSL::Token::DOT; }
        YY_BREAK
 case 38:
 YY_RULE_SETUP
-#line 97 "sksl.flex"
-{ return SkSL::Token::MINUSMINUS; }
+#line 99 "sksl.flex"
+{ return SkSL::Token::COMMA; }
        YY_BREAK
 case 39:
 YY_RULE_SETUP
-#line 99 "sksl.flex"
-{ return SkSL::Token::PLUS; }
+#line 101 "sksl.flex"
+{ return SkSL::Token::PLUSPLUS; }
        YY_BREAK
 case 40:
 YY_RULE_SETUP
-#line 101 "sksl.flex"
-{ return SkSL::Token::MINUS; }
+#line 103 "sksl.flex"
+{ return SkSL::Token::MINUSMINUS; }
        YY_BREAK
 case 41:
 YY_RULE_SETUP
-#line 103 "sksl.flex"
-{ return SkSL::Token::STAR; }
+#line 105 "sksl.flex"
+{ return SkSL::Token::PLUS; }
        YY_BREAK
 case 42:
 YY_RULE_SETUP
-#line 105 "sksl.flex"
-{ return SkSL::Token::SLASH; }
+#line 107 "sksl.flex"
+{ return SkSL::Token::MINUS; }
        YY_BREAK
 case 43:
 YY_RULE_SETUP
-#line 107 "sksl.flex"
-{ return SkSL::Token::PERCENT; }
+#line 109 "sksl.flex"
+{ return SkSL::Token::STAR; }
        YY_BREAK
 case 44:
 YY_RULE_SETUP
-#line 109 "sksl.flex"
-{ return SkSL::Token::SHL; }
+#line 111 "sksl.flex"
+{ return SkSL::Token::SLASH; }
        YY_BREAK
 case 45:
 YY_RULE_SETUP
-#line 111 "sksl.flex"
-{ return SkSL::Token::SHR; }
+#line 113 "sksl.flex"
+{ return SkSL::Token::PERCENT; }
        YY_BREAK
 case 46:
 YY_RULE_SETUP
-#line 113 "sksl.flex"
-{ return SkSL::Token::BITWISEOR; }
+#line 115 "sksl.flex"
+{ return SkSL::Token::SHL; }
        YY_BREAK
 case 47:
 YY_RULE_SETUP
-#line 115 "sksl.flex"
-{ return SkSL::Token::BITWISEXOR; }
+#line 117 "sksl.flex"
+{ return SkSL::Token::SHR; }
        YY_BREAK
 case 48:
 YY_RULE_SETUP
-#line 117 "sksl.flex"
-{ return SkSL::Token::BITWISEAND; }
+#line 119 "sksl.flex"
+{ return SkSL::Token::BITWISEOR; }
        YY_BREAK
 case 49:
 YY_RULE_SETUP
-#line 119 "sksl.flex"
-{ return SkSL::Token::LOGICALOR; }
+#line 121 "sksl.flex"
+{ return SkSL::Token::BITWISEXOR; }
        YY_BREAK
 case 50:
 YY_RULE_SETUP
-#line 121 "sksl.flex"
-{ return SkSL::Token::LOGICALXOR; }
+#line 123 "sksl.flex"
+{ return SkSL::Token::BITWISEAND; }
        YY_BREAK
 case 51:
 YY_RULE_SETUP
-#line 123 "sksl.flex"
-{ return SkSL::Token::LOGICALAND; }
+#line 125 "sksl.flex"
+{ return SkSL::Token::LOGICALOR; }
        YY_BREAK
 case 52:
 YY_RULE_SETUP
-#line 125 "sksl.flex"
-{ return SkSL::Token::NOT; }
+#line 127 "sksl.flex"
+{ return SkSL::Token::LOGICALXOR; }
        YY_BREAK
 case 53:
 YY_RULE_SETUP
-#line 127 "sksl.flex"
-{ return SkSL::Token::QUESTION; }
+#line 129 "sksl.flex"
+{ return SkSL::Token::LOGICALAND; }
        YY_BREAK
 case 54:
 YY_RULE_SETUP
-#line 129 "sksl.flex"
-{ return SkSL::Token::COLON; }
+#line 131 "sksl.flex"
+{ return SkSL::Token::NOT; }
        YY_BREAK
 case 55:
 YY_RULE_SETUP
-#line 131 "sksl.flex"
-{ return SkSL::Token::EQ; }
+#line 133 "sksl.flex"
+{ return SkSL::Token::QUESTION; }
        YY_BREAK
 case 56:
 YY_RULE_SETUP
-#line 133 "sksl.flex"
-{ return SkSL::Token::EQEQ; }
+#line 135 "sksl.flex"
+{ return SkSL::Token::COLON; }
        YY_BREAK
 case 57:
 YY_RULE_SETUP
-#line 135 "sksl.flex"
-{ return SkSL::Token::NEQ; }
+#line 137 "sksl.flex"
+{ return SkSL::Token::EQ; }
        YY_BREAK
 case 58:
 YY_RULE_SETUP
-#line 137 "sksl.flex"
-{ return SkSL::Token::GT; }
+#line 139 "sksl.flex"
+{ return SkSL::Token::EQEQ; }
        YY_BREAK
 case 59:
 YY_RULE_SETUP
-#line 139 "sksl.flex"
-{ return SkSL::Token::LT; }
+#line 141 "sksl.flex"
+{ return SkSL::Token::NEQ; }
        YY_BREAK
 case 60:
 YY_RULE_SETUP
-#line 141 "sksl.flex"
-{ return SkSL::Token::GTEQ; }
+#line 143 "sksl.flex"
+{ return SkSL::Token::GT; }
        YY_BREAK
 case 61:
 YY_RULE_SETUP
-#line 143 "sksl.flex"
-{ return SkSL::Token::LTEQ; }
+#line 145 "sksl.flex"
+{ return SkSL::Token::LT; }
        YY_BREAK
 case 62:
 YY_RULE_SETUP
-#line 145 "sksl.flex"
-{ return SkSL::Token::PLUSEQ; }
+#line 147 "sksl.flex"
+{ return SkSL::Token::GTEQ; }
        YY_BREAK
 case 63:
 YY_RULE_SETUP
-#line 147 "sksl.flex"
-{ return SkSL::Token::MINUSEQ; }
+#line 149 "sksl.flex"
+{ return SkSL::Token::LTEQ; }
        YY_BREAK
 case 64:
 YY_RULE_SETUP
-#line 149 "sksl.flex"
-{ return SkSL::Token::STAREQ; }
+#line 151 "sksl.flex"
+{ return SkSL::Token::PLUSEQ; }
        YY_BREAK
 case 65:
 YY_RULE_SETUP
-#line 151 "sksl.flex"
-{ return SkSL::Token::SLASHEQ; }
+#line 153 "sksl.flex"
+{ return SkSL::Token::MINUSEQ; }
        YY_BREAK
 case 66:
 YY_RULE_SETUP
-#line 153 "sksl.flex"
-{ return SkSL::Token::PERCENTEQ; }
+#line 155 "sksl.flex"
+{ return SkSL::Token::STAREQ; }
        YY_BREAK
 case 67:
 YY_RULE_SETUP
-#line 155 "sksl.flex"
-{ return SkSL::Token::SHLEQ; }
+#line 157 "sksl.flex"
+{ return SkSL::Token::SLASHEQ; }
        YY_BREAK
 case 68:
 YY_RULE_SETUP
-#line 157 "sksl.flex"
-{ return SkSL::Token::SHREQ; }
+#line 159 "sksl.flex"
+{ return SkSL::Token::PERCENTEQ; }
        YY_BREAK
 case 69:
 YY_RULE_SETUP
-#line 159 "sksl.flex"
-{ return SkSL::Token::BITWISEOREQ; }
+#line 161 "sksl.flex"
+{ return SkSL::Token::SHLEQ; }
        YY_BREAK
 case 70:
 YY_RULE_SETUP
-#line 161 "sksl.flex"
-{ return SkSL::Token::BITWISEXOREQ; }
+#line 163 "sksl.flex"
+{ return SkSL::Token::SHREQ; }
        YY_BREAK
 case 71:
 YY_RULE_SETUP
-#line 163 "sksl.flex"
-{ return SkSL::Token::BITWISEANDEQ; }
+#line 165 "sksl.flex"
+{ return SkSL::Token::BITWISEOREQ; }
        YY_BREAK
 case 72:
 YY_RULE_SETUP
-#line 165 "sksl.flex"
-{ return SkSL::Token::LOGICALOREQ; }
+#line 167 "sksl.flex"
+{ return SkSL::Token::BITWISEXOREQ; }
        YY_BREAK
 case 73:
 YY_RULE_SETUP
-#line 167 "sksl.flex"
-{ return SkSL::Token::LOGICALXOREQ; }
+#line 169 "sksl.flex"
+{ return SkSL::Token::BITWISEANDEQ; }
        YY_BREAK
 case 74:
 YY_RULE_SETUP
-#line 169 "sksl.flex"
-{ return SkSL::Token::LOGICALANDEQ; }
+#line 171 "sksl.flex"
+{ return SkSL::Token::LOGICALOREQ; }
        YY_BREAK
 case 75:
 YY_RULE_SETUP
-#line 171 "sksl.flex"
-{ return SkSL::Token::SEMICOLON; }
+#line 173 "sksl.flex"
+{ return SkSL::Token::LOGICALXOREQ; }
        YY_BREAK
 case 76:
 YY_RULE_SETUP
-#line 173 "sksl.flex"
-/* line comment */
+#line 175 "sksl.flex"
+{ return SkSL::Token::LOGICALANDEQ; }
        YY_BREAK
 case 77:
-/* rule 77 can match eol */
 YY_RULE_SETUP
-#line 175 "sksl.flex"
-/* block comment */
+#line 177 "sksl.flex"
+{ return SkSL::Token::SEMICOLON; }
        YY_BREAK
 case 78:
-/* rule 78 can match eol */
 YY_RULE_SETUP
-#line 177 "sksl.flex"
-/* whitespace */
+#line 179 "sksl.flex"
+/* line comment */
        YY_BREAK
 case 79:
+/* rule 79 can match eol */
 YY_RULE_SETUP
-#line 179 "sksl.flex"
-{ return SkSL::Token::INVALID_TOKEN; }
+#line 181 "sksl.flex"
+/* block comment */
        YY_BREAK
 case 80:
+/* rule 80 can match eol */
 YY_RULE_SETUP
-#line 181 "sksl.flex"
+#line 183 "sksl.flex"
+/* whitespace */
+       YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 185 "sksl.flex"
+{ return SkSL::Token::INVALID_TOKEN; }
+       YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 187 "sksl.flex"
 ECHO;
        YY_BREAK
-#line 1299 "lex.sksl.c"
+#line 1329 "lex.sksl.c"
 case YY_STATE_EOF(INITIAL):
        yyterminate();
 
@@ -1496,7 +1526,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                        { /* Not enough room in the buffer - grow it. */
 
                        /* just a shorter name for the current buffer */
-                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
                        int yy_c_buf_p_offset =
                                (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
@@ -1596,7 +1626,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                        {
                        yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 185 )
+                       if ( yy_current_state >= 201 )
                                yy_c = yy_meta[(unsigned int) yy_c];
                        }
                yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1625,12 +1655,13 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                {
                yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 185 )
+               if ( yy_current_state >= 201 )
                        yy_c = yy_meta[(unsigned int) yy_c];
                }
        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 184);
+       yy_is_jam = (yy_current_state == 200);
 
+       (void)yyg;
        return yy_is_jam ? 0 : yy_current_state;
 }
 
@@ -1725,7 +1756,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                                case EOB_ACT_END_OF_FILE:
                                        {
                                        if ( skslwrap(yyscanner ) )
-                                               return 0;
+                                               return EOF;
 
                                        if ( ! yyg->yy_did_buffer_switch_on_eof )
                                                YY_NEW_FILE;
@@ -2081,8 +2112,8 @@ YY_BUFFER_STATE sksl_scan_string (yyconst char * yystr , yyscan_t yyscanner)
 
 /** Setup the input buffer state to scan the given bytes. The next call to sksllex() will
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  */
@@ -2090,7 +2121,8 @@ YY_BUFFER_STATE sksl_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_le
 {
        YY_BUFFER_STATE b;
        char *buf;
-       yy_size_t n, i;
+       yy_size_t n;
+       int i;
     
        /* Get memory for full buffer, including space for trailing EOB's. */
        n = _yybytes_len + 2;
@@ -2236,7 +2268,7 @@ void skslset_lineno (int  line_number , yyscan_t yyscanner)
 
         /* lineno is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           yy_fatal_error( "skslset_lineno called with no buffer" , yyscanner); 
+           YY_FATAL_ERROR( "skslset_lineno called with no buffer" );
     
     yylineno = line_number;
 }
@@ -2251,7 +2283,7 @@ void skslset_column (int  column_no , yyscan_t yyscanner)
 
         /* column is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           yy_fatal_error( "skslset_column called with no buffer" , yyscanner); 
+           YY_FATAL_ERROR( "skslset_column called with no buffer" );
     
     yycolumn = column_no;
 }
@@ -2463,7 +2495,7 @@ void skslfree (void * ptr , yyscan_t yyscanner)
 
 #define YYTABLES_NAME "yytables"
 
-#line 181 "sksl.flex"
+#line 187 "sksl.flex"
 
 
 
index cbc938a..67b48e9 100644 (file)
@@ -68,6 +68,10 @@ mediump { return SkSL::Token::MEDIUMP; }
 
 highp { return SkSL::Token::HIGHP; }
 
+flat { return SkSL::Token::FLAT; }
+
+noperspective { return SkSL::Token::NOPERSPECTIVE; }
+
 struct { return SkSL::Token::STRUCT; }
 
 layout { return SkSL::Token::LAYOUT; }
diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp
new file mode 100644 (file)
index 0000000..3906f67
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSLCompiler.h"
+
+#include "Test.h"
+
+static void test(skiatest::Reporter* r, const char* src, SkSL::GLCaps caps, const char* expected) {
+    SkSL::Compiler compiler;
+    std::string output;
+    bool result = compiler.toGLSL(SkSL::Program::kFragment_Kind, src, caps, &output);
+    if (!result) {
+        SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
+    }
+    REPORTER_ASSERT(r, result);
+    if (result) {
+        if (output != expected) {
+            SkDebugf("GLSL MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src, 
+                     expected, output.c_str());
+        }
+        REPORTER_ASSERT(r, output == expected);
+    }
+}
+
+DEF_TEST(SkSLHelloWorld, r) {
+    SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
+    test(r,
+         "out vec4 fragColor; void main() { fragColor = vec4(0.75); }",
+         caps,
+         "#version 400\n"
+         "out vec4 fragColor;\n"
+         "void main() {\n"
+         "    fragColor = vec4(0.75);\n"
+         "}\n");
+}
+
+DEF_TEST(SkSLControl, r) {
+    SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
+    test(r,
+         "out vec4 fragColor;"
+         "void main() {"
+         "if (1 + 2 + 3 > 5) { fragColor = vec4(0.75); } else { discard; }"
+         "int i = 0;"
+         "while (i < 10) fragColor *= 0.5;"
+         "do { fragColor += 0.01; } while (fragColor.x < 0.7);"
+         "for (int i = 0; i < 10; i++) {"
+         "if (i % 0 == 1) break; else continue;"
+         "}"
+         "return;"
+         "}",
+         caps,
+         "#version 400\n"
+         "out vec4 fragColor;\n"
+         "void main() {\n"
+         "    if ((1 + 2) + 3 > 5) {\n"
+         "        fragColor = vec4(0.75);\n"
+         "    } else {\n"
+         "        discard;\n"
+         "    }\n"
+         "    int i = 0;\n"
+         "    while (i < 10) fragColor *= 0.5;\n"
+         "    do {\n"
+         "        fragColor += 0.01;\n"
+         "    } while (fragColor.x < 0.7);\n"
+         "    for (int i = 0;i < 10; i++) {\n"
+         "        if (i % 0 == 1) break; else continue;\n"
+         "    }\n"
+         "    return;\n"
+         "}\n");
+}
+
+DEF_TEST(SkSLFunctions, r) {
+    SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
+    test(r,
+         "out vec4 fragColor;"
+         "float foo(float v[2]) { return v[0] * v[1]; }"
+         "void bar(inout float x) { float y[2], z; y[0] = x; y[1] = x * 2; z = foo(y); x = z; }"
+         "void main() { float x = 10; bar(x); fragColor = vec4(x); }",
+         caps,
+         "#version 400\n"
+         "out vec4 fragColor;\n"
+         "float foo(in float[2] v) {\n"
+         "    return v[0] * v[1];\n"
+         "}\n"
+         "void bar(inout float x) {\n"
+         "    float y[2], z;\n"
+         "    y[0] = x;\n"
+         "    y[1] = x * 2;\n"
+         "    z = foo(y);\n"
+         "    x = z;\n"
+         "}\n"
+         "void main() {\n"
+         "    float x = 10;\n"
+         "    bar(x);\n"
+         "    fragColor = vec4(x);\n"
+         "}\n");
+}
+
+DEF_TEST(SkSLOperators, r) {
+    SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
+    test(r,
+         "void main() {"
+         "float x = 1, y = 2;"
+         "int z = 3;"
+         "x = x + y * z * x * (y - z);"
+         "y = x / y / z;"
+         "z = (z / 2 % 3 << 4) >> 2 << 1;"
+         "bool b = (x > 4) == x < 2 || 2 >= 5 && y <= z && 12 != 11;"
+         "x += 12;"
+         "x -= 12;"
+         "x *= y /= z = 10;"
+         "b ||= false;"
+         "b &&= true;"
+         "b ^^= false;"
+         "z |= 0;"
+         "z &= -1;"
+         "z ^= 0;"
+         "z >>= 2;"
+         "z <<= 4;"
+         "z %= 5;"
+         "}",
+         caps,
+         "#version 400\n"
+         "void main() {\n"
+         "    float x = 1, y = 2;\n"
+         "    int z = 3;\n"
+         "    x = x + ((y * float(z)) * x) * (y - float(z));\n"
+         "    y = (x / y) / float(z);\n"
+         "    z = (((z / 2) % 3 << 4) >> 2) << 1;\n"
+         "    bool b = x > 4 == x < 2 || (2 >= 5 && y <= float(z)) && 12 != 11;\n"
+         "    x += 12;\n"
+         "    x -= 12;\n"
+         "    x *= (y /= float(z = 10));\n"
+         "    b ||= false;\n"
+         "    b &&= true;\n"
+         "    b ^^= false;\n"
+         "    z |= 0;\n"
+         "    z &= -1;\n"
+         "    z ^= 0;\n"
+         "    z >>= 2;\n"
+         "    z <<= 4;\n"
+         "    z %= 5;\n"
+         "}\n");
+}
+
+DEF_TEST(SkSLMatrices, r) {
+    SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
+    test(r,
+         "void main() {"
+         "mat2x4 x = mat2x4(1);"
+         "mat3x2 y = mat3x2(1, 0, 0, 1, vec2(2, 2));"
+         "mat3x4 z = x * y;"
+         "vec3 v1 = mat3(1) * vec3(1);"
+         "vec3 v2 = vec3(1) * mat3(1);"
+         "}",
+         caps,
+         "#version 400\n"
+         "void main() {\n"
+         "    mat2x4 x = mat2x4(1);\n"
+         "    mat3x2 y = mat3x2(1, 0, 0, 1, vec2(2, 2));\n"
+         "    mat3x4 z = x * y;\n"
+         "    vec3 v1 = mat3(1) * vec3(1);\n"
+         "    vec3 v2 = vec3(1) * mat3(1);\n"
+         "}\n");
+}
+
+DEF_TEST(SkSLInterfaceBlock, r) {
+    SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
+    test(r,
+         "uniform testBlock {"
+         "float x;"
+         "float y[2];"
+         "layout(binding=12) mat3x2 z;"
+         "bool w;"
+         "};"
+         "void main() {"
+         "}",
+         caps,
+         "#version 400\n"
+         "uniform testBlock {\n"
+         "    float x;\n"
+         "    float[2] y;\n"
+         "    layout (binding = 12)mat3x2 z;\n"
+         "    bool w;\n"
+         "};\n"
+         "void main() {\n"
+         "}\n");
+}
+
+DEF_TEST(SkSLStructs, r) {
+    SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
+    test(r,
+         "struct A {"
+         "int x;"
+         "int y;"
+         "} a1, a2;"
+         "A a3;"
+         "struct B {"
+         "float x;"
+         "float y[2];"
+         "layout(binding=1) A z;"
+         "};"
+         "B b1, b2, b3;"
+         "void main() {"
+         "}",
+         caps,
+         "#version 400\n"
+         "struct A {\n"
+         "    int x;\n"
+         "    int y;\n"
+         "}\n"
+         " a1, a2;\n"
+         "A a3;\n"
+         "struct B {\n"
+         "    float x;\n"
+         "    float[2] y;\n"
+         "    layout (binding = 1)A z;\n"
+         "}\n"
+         " b1, b2, b3;\n"
+         "void main() {\n"
+         "}\n");
+
+}