Turned on SkSL->GLSL compiler
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2288033003

Committed: https://skia.googlesource.com/skia/+/9b0fe3d125f237d9884732a48414fa85fc71b4e3
Committed: https://skia.googlesource.com/skia/+/b12b3c6908c62c908b3680be01e3b5bfd30de310
Committed: https://skia.googlesource.com/skia/+/f008b0a59f45c0d4bea3e66faf3b01805009ec89
Committed: https://skia.googlesource.com/skia/+/08b2ccf398e2b81bc05d2c105837e5419899469b
Committed: https://skia.googlesource.com/skia/+/dcfe6dba4a335e50e86ff68e3252065d4197432c
Committed: https://skia.googlesource.com/skia/+/ccb1dd8f267f9d7fe7c9d0ce222ebc81b41853b3
Review-Url: https://codereview.chromium.org/2288033003
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp
index b240e45..29f1dbd 100644
--- a/src/sksl/SkSLParser.cpp
+++ b/src/sksl/SkSLParser.cpp
@@ -56,7 +56,9 @@
 #include "ast/SkSLASTIndexSuffix.h"
 #include "ast/SkSLASTInterfaceBlock.h"
 #include "ast/SkSLASTIntLiteral.h"
+#include "ast/SkSLASTModifiersDeclaration.h"
 #include "ast/SkSLASTParameter.h"
+#include "ast/SkSLASTPrecision.h"
 #include "ast/SkSLASTPrefixExpression.h"
 #include "ast/SkSLASTReturnStatement.h"
 #include "ast/SkSLASTStatement.h"
@@ -97,9 +99,13 @@
         switch (this->peek().fKind) {
             case Token::END_OF_FILE:
                 return result;
-            case Token::PRECISION:
-                this->precision();
+            case Token::PRECISION: {
+                std::unique_ptr<ASTDeclaration> precision = this->precision();
+                if (precision) {
+                    result.push_back(std::move(precision));
+                }
                 break;
+            }
             case Token::DIRECTIVE: {
                 std::unique_ptr<ASTDeclaration> decl = this->directive();
                 if (decl) {
@@ -163,29 +169,37 @@
 }
 
 /* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
-void Parser::precision() {
+std::unique_ptr<ASTDeclaration> Parser::precision() {
     if (!this->expect(Token::PRECISION, "'precision'")) {
-        return;
+        return nullptr;
     }
+    Modifiers::Flag result;
     Token p = this->nextToken();
     switch (p.fKind) {
-        case Token::LOWP: // fall through
-        case Token::MEDIUMP: // fall through
+        case Token::LOWP:
+            result = Modifiers::kLowp_Flag;
+            break;
+        case Token::MEDIUMP:
+            result = Modifiers::kMediump_Flag;
+            break;
         case Token::HIGHP:
-            // ignored for now
+            result = Modifiers::kHighp_Flag;
             break;
         default:
             this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" + 
                                      p.fText + "'");
-            return;
+            return nullptr;
     }
+    // FIXME handle the type
     if (!this->type()) {
-        return;
+        return nullptr;
     }
     this->expect(Token::SEMICOLON, "';'");
+    return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fPosition, result));
 }
 
-/* DIRECTIVE(#version) INT_LITERAL | DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
+/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? | 
+   DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
 std::unique_ptr<ASTDeclaration> Parser::directive() {
     Token start;
     if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
@@ -193,7 +207,12 @@
     }
     if (start.fText == "#version") {
         this->expect(Token::INT_LITERAL, "a version number");
-        // ignored for now
+        Token next = this->peek();
+        if (next.fText == "es" || next.fText == "compatibility") {
+            this->nextToken();
+        }
+        // version is ignored for now; it will eventually become an error when we stop pretending
+        // to be GLSL
         return nullptr;
     } else if (start.fText == "#extension") {
         Token name;
@@ -227,6 +246,10 @@
     if (lookahead.fKind == Token::STRUCT) {
         return this->structVarDeclaration(modifiers);
     }
+    if (lookahead.fKind == Token::SEMICOLON) {
+        this->nextToken();
+        return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
+    }
     std::unique_ptr<ASTType> type(this->type());
     if (!type) {
         return nullptr;
@@ -477,10 +500,13 @@
     int set = -1;
     int builtin = -1;
     bool originUpperLeft = false;
+    bool overrideCoverage = false;
+    bool blendSupportAllEquations = false;
     if (this->peek().fKind == Token::LAYOUT) {
         this->nextToken();
         if (!this->expect(Token::LPAREN, "'('")) {
-            return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
+            return ASTLayout(location, binding, index, set, builtin, originUpperLeft,
+                             overrideCoverage, blendSupportAllEquations);
         }
         for (;;) {
             Token t = this->nextToken();
@@ -496,6 +522,10 @@
                 builtin = this->layoutInt();
             } else if (t.fText == "origin_upper_left") {
                 originUpperLeft = true;
+            } else if (t.fText == "override_coverage") {
+                overrideCoverage = true;
+            } else if (t.fText == "blend_support_all_equations") {
+                blendSupportAllEquations = true;
             } else {
                 this->error(t.fPosition, ("'" + t.fText + 
                                           "' is not a valid layout qualifier").c_str());
@@ -509,7 +539,8 @@
             }
         }
     }
-    return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
+    return ASTLayout(location, binding, index, set, builtin, originUpperLeft, overrideCoverage,
+                     blendSupportAllEquations);
 }
 
 /* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */
@@ -1211,10 +1242,11 @@
 /* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
 std::unique_ptr<ASTExpression> Parser::unaryExpression() {
     switch (this->peek().fKind) {
-        case Token::PLUS:     // fall through
-        case Token::MINUS:    // fall through
-        case Token::NOT:      // fall through
-        case Token::PLUSPLUS: // fall through
+        case Token::PLUS:       // fall through
+        case Token::MINUS:      // fall through
+        case Token::LOGICALNOT: // fall through
+        case Token::BITWISENOT: // fall through
+        case Token::PLUSPLUS:   // fall through
         case Token::MINUSMINUS: {
             Token t = this->nextToken();
             std::unique_ptr<ASTExpression> expr = this->unaryExpression();
@@ -1254,12 +1286,16 @@
     }
 }
 
-/* LBRACKET expression RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN | 
+/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN | 
    PLUSPLUS | MINUSMINUS */
 std::unique_ptr<ASTSuffix> Parser::suffix() {
     Token next = this->nextToken();
     switch (next.fKind) {
         case Token::LBRACKET: {
+            if (this->peek().fKind == Token::RBRACKET) {
+                this->nextToken();
+                return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fPosition));
+            }
             std::unique_ptr<ASTExpression> e = this->expression();
             if (!e) {
                 return nullptr;