Move grammar closer to official grammar.

Note that this involved lots of changes to the syntax highlighter,
since that is now doing some of the heavy lifting that the grammar
previously did.

Change-Id: I23e2133363ae08c6d9f944002c4f112eb43cf9bf
diff --git a/src/fuchsia/developer/plugin/fidl/BUILD b/src/fuchsia/developer/plugin/fidl/BUILD
index f36287b..716bbd8 100644
--- a/src/fuchsia/developer/plugin/fidl/BUILD
+++ b/src/fuchsia/developer/plugin/fidl/BUILD
@@ -23,16 +23,16 @@
     ],
 )
 
+# Regenerate with something like:
+# find . -name \*.java | sort | sed -e "s|./\(.*\)|    \"\\1\",|"
 GEN_SRCS_PARSE = [
     "fuchsia/developer/plugin/fidl/parser/Parser.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlArrayType.java",
     "fuchsia/developer/plugin/fidl/psi/FidlAttribute.java",
     "fuchsia/developer/plugin/fidl/psi/FidlAttributeList.java",
     "fuchsia/developer/plugin/fidl/psi/FidlAttributes.java",
     "fuchsia/developer/plugin/fidl/psi/FidlBitsDeclaration.java",
     "fuchsia/developer/plugin/fidl/psi/FidlBitsOrEnumMember.java",
     "fuchsia/developer/plugin/fidl/psi/FidlBitsOrEnumMemberValue.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlBoundaryConstant.java",
     "fuchsia/developer/plugin/fidl/psi/FidlBracketAttributeList.java",
     "fuchsia/developer/plugin/fidl/psi/FidlCompoundIdentifier.java",
     "fuchsia/developer/plugin/fidl/psi/FidlConstant.java",
@@ -44,8 +44,6 @@
     "fuchsia/developer/plugin/fidl/psi/FidlHandleSubtype.java",
     "fuchsia/developer/plugin/fidl/psi/FidlHandleType.java",
     "fuchsia/developer/plugin/fidl/psi/FidlIdentifierToken.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlIdentifierType.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlIntegerType.java",
     "fuchsia/developer/plugin/fidl/psi/FidlIntegralLiteral.java",
     "fuchsia/developer/plugin/fidl/psi/FidlLibraryHeader.java",
     "fuchsia/developer/plugin/fidl/psi/FidlLiteral.java",
@@ -54,40 +52,32 @@
     "fuchsia/developer/plugin/fidl/psi/FidlParameter.java",
     "fuchsia/developer/plugin/fidl/psi/FidlParameterList.java",
     "fuchsia/developer/plugin/fidl/psi/FidlParameters.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlPopulatedTableField.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlPrimitiveType.java",
     "fuchsia/developer/plugin/fidl/psi/FidlProtocolCompose.java",
     "fuchsia/developer/plugin/fidl/psi/FidlProtocolDeclaration.java",
     "fuchsia/developer/plugin/fidl/psi/FidlProtocolEvent.java",
     "fuchsia/developer/plugin/fidl/psi/FidlProtocolMember.java",
     "fuchsia/developer/plugin/fidl/psi/FidlProtocolMethod.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlRequestType.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlReservedTableField.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlStringType.java",
     "fuchsia/developer/plugin/fidl/psi/FidlStructDeclaration.java",
     "fuchsia/developer/plugin/fidl/psi/FidlStructField.java",
     "fuchsia/developer/plugin/fidl/psi/FidlTableDeclaration.java",
+    "fuchsia/developer/plugin/fidl/psi/FidlTableFieldDecl.java",
     "fuchsia/developer/plugin/fidl/psi/FidlTableField.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlType.java",
+    "fuchsia/developer/plugin/fidl/psi/FidlTableFieldOrdinal.java",
+    "fuchsia/developer/plugin/fidl/psi/FidlTypeConstraint.java",
+    "fuchsia/developer/plugin/fidl/psi/FidlTypeConstructor.java",
     "fuchsia/developer/plugin/fidl/psi/FidlUnionDeclaration.java",
     "fuchsia/developer/plugin/fidl/psi/FidlUnionField.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlUnsignedIntegerType.java",
     "fuchsia/developer/plugin/fidl/psi/FidlUsingDeclaration.java",
     "fuchsia/developer/plugin/fidl/psi/FidlUsing.java",
     "fuchsia/developer/plugin/fidl/psi/FidlUsingList.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlVectorAlias.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlVectorType.java",
     "fuchsia/developer/plugin/fidl/psi/FidlVisitor.java",
     "fuchsia/developer/plugin/fidl/psi/FidlXunionDeclaration.java",
-    "fuchsia/developer/plugin/fidl/psi/FidlXunionField.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlArrayTypeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlAttributeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlAttributeListImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlAttributesImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlBitsDeclarationImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlBitsOrEnumMemberImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlBitsOrEnumMemberValueImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlBoundaryConstantImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlBracketAttributeListImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlCompoundIdentifierImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlConstantImpl.java",
@@ -99,8 +89,6 @@
     "fuchsia/developer/plugin/fidl/psi/impl/FidlHandleSubtypeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlHandleTypeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlIdentifierTokenImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlIdentifierTypeImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlIntegerTypeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlIntegralLiteralImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlLibraryHeaderImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlLiteralImpl.java",
@@ -109,31 +97,25 @@
     "fuchsia/developer/plugin/fidl/psi/impl/FidlParameterImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlParameterListImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlParametersImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlPopulatedTableFieldImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlPrimitiveTypeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlProtocolComposeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlProtocolDeclarationImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlProtocolEventImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlProtocolMemberImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlProtocolMethodImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlRequestTypeImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlReservedTableFieldImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlStringTypeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlStructDeclarationImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlStructFieldImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlTableDeclarationImpl.java",
+    "fuchsia/developer/plugin/fidl/psi/impl/FidlTableFieldDeclImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlTableFieldImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlTypeImpl.java",
+    "fuchsia/developer/plugin/fidl/psi/impl/FidlTableFieldOrdinalImpl.java",
+    "fuchsia/developer/plugin/fidl/psi/impl/FidlTypeConstraintImpl.java",
+    "fuchsia/developer/plugin/fidl/psi/impl/FidlTypeConstructorImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlUnionDeclarationImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlUnionFieldImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlUnsignedIntegerTypeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlUsingDeclarationImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlUsingImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlUsingListImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlVectorAliasImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlVectorTypeImpl.java",
     "fuchsia/developer/plugin/fidl/psi/impl/FidlXunionDeclarationImpl.java",
-    "fuchsia/developer/plugin/fidl/psi/impl/FidlXunionFieldImpl.java",
     "fuchsia/developer/plugin/fidl/psi/Types.java",
 ]
 
@@ -150,18 +132,19 @@
 java_library(
     name = "fidl",
     srcs = GEN_SRCS + glob(["*.java"]) + glob(["psi/*.java"]),
-    resources = ["icons/fuchsia-logo-16x16.png",
-                 "icons/B.png",
-                 "icons/C.png",
-                 "icons/E.png",
-                 "icons/F.png",
-                 "icons/M.png",
-                 "icons/P.png",
-                 "icons/S.png",
-                 "icons/T.png",
-                 "icons/U.png",
-                 "icons/X.png",
-                 ],
+    resources = [
+        "icons/B.png",
+        "icons/C.png",
+        "icons/E.png",
+        "icons/F.png",
+        "icons/M.png",
+        "icons/P.png",
+        "icons/S.png",
+        "icons/T.png",
+        "icons/U.png",
+        "icons/X.png",
+        "icons/fuchsia-logo-16x16.png",
+    ],
     visibility = ["//visibility:public"],
     deps = [
         "@google_bazel_common//third_party/java/guava",
diff --git a/src/fuchsia/developer/plugin/fidl/ContextAwareHighlighter.java b/src/fuchsia/developer/plugin/fidl/ContextAwareHighlighter.java
index 8ff7064..db56ca6 100644
--- a/src/fuchsia/developer/plugin/fidl/ContextAwareHighlighter.java
+++ b/src/fuchsia/developer/plugin/fidl/ContextAwareHighlighter.java
@@ -1,5 +1,6 @@
 package fuchsia.developer.plugin.fidl;
 
+import com.google.common.collect.ImmutableSet;
 import com.intellij.lang.ASTNode;
 import com.intellij.lang.annotation.Annotation;
 import com.intellij.lang.annotation.AnnotationHolder;
@@ -7,54 +8,197 @@
 import com.intellij.openapi.editor.colors.TextAttributesKey;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
 import fuchsia.developer.plugin.fidl.psi.Types;
-import java.util.logging.Logger;
+import java.util.Arrays;
+import java.util.Set;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class ContextAwareHighlighter implements Annotator {
 
+  private static final TextAttributesKey KEYWORD_ATTRIBUTE;
+  private static final Set<String> TYPE_KEYWORDS;
   private static final TextAttributesKey IDENTIFIER_ATTRIBUTE;
+  private static final SyntaxHighlighter SYNTAX_HIGHLIGHTER;
+  private static final TokenSet INTEGRAL_TYPES =
+      TokenSet.create(
+          Types.INT8,
+          Types.INT16,
+          Types.INT32,
+          Types.INT64,
+          Types.UINT8,
+          Types.UINT16,
+          Types.UINT32,
+          Types.UINT64);
+  private static final TokenSet UNSIGNED_INTEGRAL_TYPES =
+      TokenSet.create(Types.UINT8, Types.UINT16, Types.UINT32, Types.UINT64);
 
   static {
-    SyntaxHighlighter highlighter = new SyntaxHighlighter();
-    TextAttributesKey[] key = highlighter.getTokenHighlights(Types.IDENTIFIER);
+    SYNTAX_HIGHLIGHTER = new SyntaxHighlighter();
+    TextAttributesKey[] key = SYNTAX_HIGHLIGHTER.getKeywordHighlights();
+    KEYWORD_ATTRIBUTE = key[0];
+
+    ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+    builder.addAll(
+        Arrays.asList(
+            "array",
+            "vector",
+            "string",
+            "handle",
+            "process",
+            "thread",
+            "vmo",
+            "channel",
+            "event",
+            "port",
+            "interrupt",
+            "log",
+            "socket",
+            "resource",
+            "eventpair",
+            "job",
+            "vmar",
+            "fifo",
+            "guest",
+            "timer",
+            "request",
+            "bool",
+            "float32",
+            "float64",
+            "int8",
+            "int16",
+            "int32",
+            "int64",
+            "uint8",
+            "uint16",
+            "uint32",
+            "uint64"));
+    TYPE_KEYWORDS = builder.build();
+
+    key = SYNTAX_HIGHLIGHTER.getTokenHighlights(Types.IDENTIFIER);
     IDENTIFIER_ATTRIBUTE = key[0];
   }
 
+  private static class NumberAndRadix {
+    String representation;
+    int radix;
+  }
+
+  private static NumberAndRadix numberAndRadix(ASTNode literalNode) {
+    NumberAndRadix out = new NumberAndRadix();
+    // Assume decimal
+    out.representation = literalNode.getText();
+    out.radix = 10;
+    if (literalNode.findChildByType(Types.BINARY_INTEGRAL_LITERAL) != null) {
+      String[] pieces = out.representation.split("0[bB]");
+      out.representation = pieces[0] + pieces[1];
+      out.radix = 2;
+    } else if (literalNode.findChildByType(Types.HEX_INTEGRAL_LITERAL) != null) {
+      String[] pieces = out.representation.split("0[xX]");
+      out.representation = pieces[0] + pieces[1];
+      out.radix = 16;
+    }
+    return out;
+  }
+
+  @Nullable
+  private static Long signedLong(ASTNode literalNode) {
+    NumberAndRadix val = numberAndRadix(literalNode);
+    Long lval;
+    try {
+      lval = Long.parseLong(val.representation, val.radix);
+    } catch (NumberFormatException e) {
+      // This may happen if you say something like "0B1234"
+      return null;
+    }
+    return lval;
+  }
+
+  @Nullable
+  private static Long unsignedLong(ASTNode literalNode) {
+    NumberAndRadix val = numberAndRadix(literalNode);
+    Long lval;
+    try {
+      lval = Long.parseUnsignedLong(val.representation, val.radix);
+    } catch (NumberFormatException e) {
+      // This may happen if you say something like "0B1234"
+      return null;
+    }
+    return lval;
+  }
+
   /**
    * @param literalNode An ASTNode of type NUMERIC_LITERAL.
    * @return null if the value associated with the node isn't supported or is an unsigned power of
    *     two, an error message otherwise.
    */
   private static String unsignedLongPowerOfTwoOrError(ASTNode literalNode) {
-    // Assume decimal
-    String value = literalNode.getText();
-    int radix = 10;
-    if (literalNode.findChildByType(Types.BINARY_INTEGRAL_LITERAL) != null) {
-      String[] pieces = value.split("0[bB]");
-      value = pieces[0] + pieces[1];
-      radix = 2;
-    } else if (literalNode.findChildByType(Types.HEX_INTEGRAL_LITERAL) != null) {
-      String[] pieces = value.split("0[xX]");
-      value = pieces[0] + pieces[1];
-      radix = 16;
-    }
-
-    Long lval = null;
-    try {
-      lval = Long.parseLong(value, radix);
-    } catch (NumberFormatException e) {
-      // Probably not worth throwing anything.
-      Logger logger = Logger.getLogger(ContextAwareHighlighter.class.getName());
-      logger.warning("Unknown numeric value " + value);
-      return null;
-    }
-    if (lval < 0 || Long.bitCount(lval) != 1) {
-      return "Bit value must be non-negative power of two, is  " + Long.toString(lval, radix);
+    Long lval = unsignedLong(literalNode);
+    if (lval == null || lval < 0 || Long.bitCount(lval) != 1) {
+      return "Bit value must be non-negative power of two, is  " + literalNode.getText();
     }
     return null;
   }
 
+  /**
+   * Checks the literal is of the (currently numeric) type given in typeConstructor.
+   *
+   * @param typeConstructor ASTNode containing the type the element is supposed to be.
+   * @param literal ASTNode containing the element to check
+   * @return A string describing the error, or null if there was no error
+   */
+  private static String correctTypeOrError(@Nullable ASTNode typeConstructor, ASTNode literal) {
+    String type;
+    if (typeConstructor == null) {
+      // Only happens with enums; this is default value for enum.
+      type = "uint32";
+    } else {
+      type = typeConstructor.getText();
+    }
+    boolean error = false;
+    Long val;
+    switch (type) {
+      case "int8":
+        val = signedLong(literal);
+        error = val == null || (val & ~0xFFL) != 0;
+        break;
+      case "int16":
+        val = signedLong(literal);
+        error = val == null || (val & ~0xFFFFL) != 0;
+        break;
+      case "int32":
+        val = signedLong(literal);
+        error = val == null || (val & ~0xFFFFFFFFL) != 0;
+        break;
+      case "int64":
+        val = signedLong(literal);
+        error = val == null;
+        break;
+      case "uint8":
+        val = unsignedLong(literal);
+        error = val == null || (val & ~0xFFL) != 0;
+        break;
+      case "uint16":
+        val = unsignedLong(literal);
+        error = val == null || (val & ~0xFFFFL) != 0;
+        break;
+      case "uint32":
+        val = unsignedLong(literal);
+        error = val == null || (val & ~0xFFFFFFFFL) != 0;
+        break;
+      case "uint64":
+        val = unsignedLong(literal);
+        error = val == null;
+        break;
+    }
+    String result = null;
+    if (error) {
+      result = "Expected value of type " + typeConstructor.getText() + ", got " + literal.getText();
+    }
+    return result;
+  }
+
   @Override
   public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
     PsiElement parent = element.getParent();
@@ -62,25 +206,108 @@
       return;
     }
     IElementType parentType = parent.getNode().getElementType();
-    if (parentType == Types.IDENTIFIER_TOKEN) {
+    IElementType thisType = element.getNode().getElementType();
+
+    // Context-sensitive keywords: if the token is used in the place of an identifier, and the
+    // SyntaxHighlighter might highlight it, then make sure it is colored as an identifier
+    if (parentType == Types.IDENTIFIER_TOKEN
+        && SYNTAX_HIGHLIGHTER.getTokenHighlights(thisType).length != 0) {
       Annotation annotation = holder.createInfoAnnotation(element, null);
       annotation.setTextAttributes(IDENTIFIER_ATTRIBUTE);
     }
 
-    if (element.getNode().getElementType() == Types.XUNION) {
-      holder.createWarningAnnotation(element,
-          "Xunions are transitional, and will be removed in a future language revision");
+    // Context-sensitive keywords, part II: The Syntax Highlighter does not color types.  If we
+    // think this identifier is a type, color it.
+    if (parentType == Types.COMPOUND_IDENTIFIER) {
+      IElementType grandParentType = parent.getParent().getNode().getElementType();
+      if (grandParentType == Types.TYPE_CONSTRUCTOR) {
+        if (TYPE_KEYWORDS.contains(element.getText())) {
+          Annotation annotation = holder.createInfoAnnotation(element, null);
+          annotation.setTextAttributes(KEYWORD_ATTRIBUTE);
+        }
+      }
     }
 
-    if (element.getNode().getElementType() == Types.BITS_OR_ENUM_MEMBER_VALUE) {
-      IElementType grandParentType = parent.getParent().getNode().getElementType();
-      if (grandParentType == Types.BITS_DECLARATION) {
-        ASTNode literalNode = element.getNode().findChildByType(Types.INTEGRAL_LITERAL);
-        if (literalNode != null) {
-          // is a numeric value
-          String value = unsignedLongPowerOfTwoOrError(literalNode);
-          if (value != null) {
-            holder.createErrorAnnotation(element, value);
+    // The enum-declaration allows the more liberal type-constructor in the grammar, but the
+    // compiler limits this to signed or unsigned integer types
+    if (parentType == Types.ENUM_DECLARATION && thisType == Types.TYPE_CONSTRUCTOR) {
+      // compound-identifier -> identifier-token -> int
+      ASTNode compoundIdentifier = element.getNode().findChildByType(Types.COMPOUND_IDENTIFIER);
+      if (compoundIdentifier != null) {
+        ASTNode identifierToken = compoundIdentifier.findChildByType(Types.IDENTIFIER_TOKEN);
+
+        if (identifierToken != null && identifierToken.findChildByType(INTEGRAL_TYPES) == null) {
+          holder.createErrorAnnotation(
+              element, "Expected integral type, found " + identifierToken.getText());
+        }
+      }
+    }
+
+    if (thisType == Types.XUNION) {
+      holder.createWarningAnnotation(
+          element,
+          "Xunions are transitional, and will be renamed to unions"
+              + " in a future language revision");
+    }
+
+    // The bits-declaration allows the more liberal type-constructor in the grammar, but the
+    // compiler limits this to unsigned integer types
+    if (parentType == Types.BITS_DECLARATION && thisType == Types.TYPE_CONSTRUCTOR) {
+      // type-constructor -> compound-identifier -> identifier-token -> int8-or-whatever
+      ASTNode compoundIdentifier = element.getNode().findChildByType(Types.COMPOUND_IDENTIFIER);
+      if (compoundIdentifier != null) {
+        ASTNode identifierToken = compoundIdentifier.findChildByType(Types.IDENTIFIER_TOKEN);
+        if (identifierToken != null
+            && identifierToken.findChildByType(UNSIGNED_INTEGRAL_TYPES) == null) {
+          holder.createErrorAnnotation(
+              element, "Expected unsigned integral type, found " + identifierToken.getText());
+        }
+      }
+    }
+
+    // The rule from the grammar:
+    // -----
+    // The bits-or-enum-member-value allows the more liberal literal in the grammar, but the
+    // compiler limits this to:
+    //
+    // - A NUMERIC-LITERAL in the context of an enum;
+    // - A NUMERIC-LITERAL which must be a power of two, in the context of a bits.
+    // -----
+    // We take it a bit farther (as does the compiler): we ensure that the types match the size of
+    // the bits or enums (they are big enough to fit into uint8 and so on).
+    if (thisType == Types.BITS_OR_ENUM_MEMBER_VALUE) {
+      ASTNode grandParent = element.getParent().getParent().getNode();
+      IElementType grandParentType = grandParent.getElementType();
+      if (grandParentType == Types.ENUM_DECLARATION || grandParentType == Types.BITS_DECLARATION) {
+        // literal -> numeric-literal -> integral-literal -> {decimal, hex, binary}-integral-literal
+        ASTNode literal = element.getNode().findChildByType(Types.LITERAL);
+        if (literal != null) {
+          ASTNode numericLiteral = literal.findChildByType(Types.NUMERIC_LITERAL);
+          if (numericLiteral == null) {
+            // Must be a numeric literal in either case:
+            holder.createErrorAnnotation(
+                element, "Expected integer value for member, found " + literal.getText());
+          } else {
+            ASTNode integralLiteral = numericLiteral.findChildByType(Types.INTEGRAL_LITERAL);
+            if (integralLiteral == null) {
+              // Must be an integral literal in either case:
+              holder.createErrorAnnotation(
+                  element, "Expected integer value for member, found " + literal.getText());
+            } else {
+              // bits/enum-declaration -> bits-or-enum-member -> bits-or-enum-member-value
+              String value =
+                  correctTypeOrError(
+                      grandParent.findChildByType(Types.TYPE_CONSTRUCTOR), integralLiteral);
+              if (value != null) {
+                holder.createErrorAnnotation(element, value);
+              }
+              if (grandParentType == Types.BITS_DECLARATION) {
+                value = unsignedLongPowerOfTwoOrError(integralLiteral);
+                if (value != null) {
+                  holder.createErrorAnnotation(element, value);
+                }
+              }
+            }
           }
         }
       }
diff --git a/src/fuchsia/developer/plugin/fidl/Fidl.bnf b/src/fuchsia/developer/plugin/fidl/Fidl.bnf
index 2440ee0..2bd11ca 100644
--- a/src/fuchsia/developer/plugin/fidl/Fidl.bnf
+++ b/src/fuchsia/developer/plugin/fidl/Fidl.bnf
@@ -18,9 +18,9 @@
 
   // The FidlNamedElements identify the elements we want to appear in the structure view.
   implements(".*-declaration")="fuchsia.developer.plugin.fidl.psi.FidlNamedElement"
-  implements("protocol-method|protocol-event|struct-field|populated-table-field|union-field|xunion-field|bits-or-enum-member")="fuchsia.developer.plugin.fidl.psi.FidlNamedElement"
+  implements("protocol-method|protocol-event|struct-field|union-field|bits-or-enum-member")="fuchsia.developer.plugin.fidl.psi.FidlNamedElement"
   extends(".*-declaration")="fuchsia.developer.plugin.fidl.psi.FidlNamedElementImpl"
-  extends("protocol-method|protocol-event|struct-field|populated-table-field|union-field|xunion-field|bits-or-enum-member")="fuchsia.developer.plugin.fidl.psi.FidlNamedElementImpl"
+  extends("protocol-method|protocol-event|struct-field|union-field|bits-or-enum-member")="fuchsia.developer.plugin.fidl.psi.FidlNamedElementImpl"
 
   tokens = [
     line_comment="regexp://.*"
@@ -33,7 +33,7 @@
 
 using-list ::= ( using | using-declaration )*
 
-using-declaration ::= USING_T identifier-token EQUALS type SEMICOLON
+using-declaration ::= USING_T identifier-token EQUALS type-constructor SEMICOLON
 
 declaration-list ::= ( declaration SEMICOLON )*
 
@@ -50,26 +50,24 @@
                 union-declaration |
                 xunion-declaration
 
-const-declaration ::= attribute-list? CONST type identifier-token EQUALS constant
+const-declaration ::= attribute-list? CONST type-constructor identifier-token EQUALS constant
 
-enum-declaration ::= attribute-list? ENUM identifier-token ( COLON integer-type )?
+enum-declaration ::= attribute-list? ENUM identifier-token ( COLON type-constructor )?
                    OBRACE ( bits-or-enum-member SEMICOLON )+  CBRACE
 
-bits-declaration ::= attribute-list? BITS identifier-token ( COLON unsigned-integer-type )
+bits-declaration ::= attribute-list? BITS identifier-token ( COLON type-constructor )
                      OBRACE ( bits-or-enum-member  SEMICOLON )+ CBRACE
 
 bits-or-enum-member ::= attribute-list? identifier-token EQUALS bits-or-enum-member-value
 
-bits-or-enum-member-value ::= identifier-token | integral-literal
+bits-or-enum-member-value ::= identifier-token | literal
 
 protocol-declaration ::= attribute-list? PROTOCOL identifier-token
                          OBRACE ( protocol-member SEMICOLON )* CBRACE
 
-protocol-member ::= protocol-compose | protocol-method | protocol-event
+protocol-member ::= protocol-method | protocol-event | protocol-compose
 
-protocol-compose ::= COMPOSE compound-identifier
-
-protocol-method ::= attribute-list? identifier-token parameter-list ( ARROW parameter-list )? ( ERROR type )?
+protocol-method ::= attribute-list? identifier-token parameter-list ( ARROW parameter-list ( ERROR type-constructor )? )?
 
 protocol-event ::= attribute-list? ARROW identifier-token parameter-list
 
@@ -77,27 +75,29 @@
 
 parameters ::= parameter ( COMMA parameter )*
 
-parameter ::= type identifier-token
+parameter ::= type-constructor identifier-token
+
+protocol-compose ::= COMPOSE compound-identifier
 
 struct-declaration ::= attribute-list? STRUCT identifier-token OBRACE ( struct-field SEMICOLON )* CBRACE
 
-struct-field ::= attribute-list? type identifier-token ( EQUALS constant )?
-
-table-declaration ::= attribute-list? TABLE identifier-token OBRACE ( attribute-list? table-field SEMICOLON )* CBRACE
-
-table-field ::= populated-table-field | reserved-table-field
-
-populated-table-field ::= attribute-list? ordinal COLON type identifier-token ( EQUALS constant )?
-
-reserved-table-field ::= ordinal COLON RESERVED
+struct-field ::= attribute-list? type-constructor identifier-token ( EQUALS constant )?
 
 union-declaration ::= attribute-list? UNION identifier-token OBRACE ( union-field SEMICOLON )+ CBRACE
 
-union-field ::= attribute-list? type identifier-token
+xunion-declaration ::= attribute-list? XUNION identifier-token OBRACE ( union-field SEMICOLON )+ CBRACE
 
-xunion-declaration ::= attribute-list? XUNION identifier-token OBRACE ( xunion-field SEMICOLON )+ CBRACE
+union-field ::= attribute-list? type-constructor identifier-token
 
-xunion-field ::= attribute-list? type identifier-token
+table-declaration ::= attribute-list? TABLE identifier-token OBRACE ( attribute-list? table-field SEMICOLON )* CBRACE
+
+table-field ::= attribute-list? table-field-ordinal table-field-decl
+
+table-field-ordinal ::= ordinal COLON
+
+// Diff from master grammar: decl instead of declaration, because declaration is reserved for named
+// things.
+table-field-decl ::= struct-field | RESERVED
 
 attribute-list ::= doc-attribute-list | bracket-attribute-list
 
@@ -105,41 +105,24 @@
 
 bracket-attribute-list ::= OBRACKET attributes CBRACKET
 
+// Slightly different from master grammar for ease of parsing
 attributes ::= attribute ( COMMA attribute )*
 
 attribute ::= identifier-token ( EQUALS STRING_LITERAL )?
 
-type ::= array-type | vector-type | string-type | handle-type
-                       | request-type | primitive-type | identifier-type
-
-identifier-type ::= compound-identifier ( QUESTION )?
-
-array-type ::= ARRAY LANGLE type RANGLE COLON boundary-constant
-
-vector-type ::= vector-alias ( COLON boundary-constant )? ( QUESTION )?
-
-vector-alias ::= VECTOR LANGLE type RANGLE | BYTES
-
-string-type ::= STRING ( COLON boundary-constant )? ( QUESTION )?
+type-constructor ::= compound-identifier ( LANGLE type-constructor RANGLE )? type-constraint? ( QUESTION )?
+                    | handle-type
 
 handle-type ::= HANDLE ( LANGLE handle-subtype RANGLE )? ( QUESTION )?
 
 handle-subtype ::= PROCESS | THREAD | VMO | CHANNEL | EVENT | PORT |
-                 INTERRUPT | LOG | SOCKET | RESOURCE | EVENTPAIR |
-                 JOB | VMAR | FIFO | GUEST | TIMER
+                   INTERRUPT | LOG | SOCKET | RESOURCE | EVENTPAIR |
+                   JOB | VMAR | FIFO | GUEST | TIMER
 
-request-type ::= REQUEST LANGLE compound-identifier RANGLE ( QUESTION )?
-
-primitive-type ::= integer-type | BOOL | FLOAT32 | FLOAT64
-
-integer-type ::= INT8 | INT16 | INT32 | INT64 | unsigned-integer-type
-
-unsigned-integer-type ::= UINT8 | UINT16 | UINT32 | UINT64
+type-constraint ::= COLON constant ;
 
 constant ::= compound-identifier | literal
 
-boundary-constant ::= compound-identifier | integral-literal
-
 ordinal ::= integral-literal
 
 literal ::= STRING_LITERAL | numeric-literal | TRUE | FALSE
diff --git a/src/fuchsia/developer/plugin/fidl/SyntaxHighlighter.java b/src/fuchsia/developer/plugin/fidl/SyntaxHighlighter.java
index f324e57..17fe027 100644
--- a/src/fuchsia/developer/plugin/fidl/SyntaxHighlighter.java
+++ b/src/fuchsia/developer/plugin/fidl/SyntaxHighlighter.java
@@ -90,39 +90,7 @@
             Types.UNION,
             Types.XUNION,
             Types.ERROR,
-            Types.ARRAY,
-            Types.VECTOR,
-            Types.STRING,
-            Types.HANDLE,
-            Types.PROCESS,
-            Types.THREAD,
-            Types.VMO,
-            Types.CHANNEL,
-            Types.EVENT,
-            Types.PORT,
-            Types.INTERRUPT,
-            Types.LOG,
-            Types.SOCKET,
-            Types.RESOURCE,
-            Types.EVENTPAIR,
-            Types.JOB,
-            Types.VMAR,
-            Types.FIFO,
-            Types.GUEST,
-            Types.TIMER,
-            Types.REQUEST,
             Types.RESERVED,
-            Types.BOOL,
-            Types.FLOAT32,
-            Types.FLOAT64,
-            Types.INT8,
-            Types.INT16,
-            Types.INT32,
-            Types.INT64,
-            Types.UINT8,
-            Types.UINT16,
-            Types.UINT32,
-            Types.UINT64,
             Types.TRUE,
             Types.FALSE)) {
       builder.put(key, KEYWORD_KEYS);
@@ -159,4 +127,8 @@
   public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
     return HIGHLIGHT_TYPES.getOrDefault(tokenType, EMPTY_KEYS);
   }
+
+  public TextAttributesKey[] getKeywordHighlights() {
+    return KEYWORD_KEYS;
+  }
 }
diff --git a/src/fuchsia/developer/plugin/fidl/psi/FidlNamedElement.java b/src/fuchsia/developer/plugin/fidl/psi/FidlNamedElement.java
index d142580..5ebdb8b 100644
--- a/src/fuchsia/developer/plugin/fidl/psi/FidlNamedElement.java
+++ b/src/fuchsia/developer/plugin/fidl/psi/FidlNamedElement.java
@@ -5,7 +5,6 @@
 package fuchsia.developer.plugin.fidl.psi;
 
 import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiNamedElement;
 import org.jetbrains.annotations.NotNull;
 
 public interface FidlNamedElement extends PsiElement {
diff --git a/src/fuchsia/developer/plugin/fidl/psi/FidlNamedElementImpl.java b/src/fuchsia/developer/plugin/fidl/psi/FidlNamedElementImpl.java
index a5e787b..ff72149 100644
--- a/src/fuchsia/developer/plugin/fidl/psi/FidlNamedElementImpl.java
+++ b/src/fuchsia/developer/plugin/fidl/psi/FidlNamedElementImpl.java
@@ -14,7 +14,6 @@
 import fuchsia.developer.plugin.fidl.psi.impl.FidlBitsOrEnumMemberImpl;
 import fuchsia.developer.plugin.fidl.psi.impl.FidlConstDeclarationImpl;
 import fuchsia.developer.plugin.fidl.psi.impl.FidlEnumDeclarationImpl;
-import fuchsia.developer.plugin.fidl.psi.impl.FidlPopulatedTableFieldImpl;
 import fuchsia.developer.plugin.fidl.psi.impl.FidlProtocolDeclarationImpl;
 import fuchsia.developer.plugin.fidl.psi.impl.FidlProtocolEventImpl;
 import fuchsia.developer.plugin.fidl.psi.impl.FidlProtocolMethodImpl;
@@ -25,7 +24,6 @@
 import fuchsia.developer.plugin.fidl.psi.impl.FidlUnionFieldImpl;
 import fuchsia.developer.plugin.fidl.psi.impl.FidlUsingDeclarationImpl;
 import fuchsia.developer.plugin.fidl.psi.impl.FidlXunionDeclarationImpl;
-import fuchsia.developer.plugin.fidl.psi.impl.FidlXunionFieldImpl;
 import java.util.Map;
 import javax.swing.Icon;
 import org.jetbrains.annotations.NotNull;
@@ -53,9 +51,7 @@
             .put(FidlProtocolMethodImpl.class, IconLoader.getIcon(path + "M.png"))
             .put(FidlProtocolEventImpl.class, IconLoader.getIcon(path + "E.png"))
             .put(FidlStructFieldImpl.class, IconLoader.getIcon(path + "F.png"))
-            .put(FidlPopulatedTableFieldImpl.class, IconLoader.getIcon(path + "F.png"))
             .put(FidlUnionFieldImpl.class, IconLoader.getIcon(path + "F.png"))
-            .put(FidlXunionFieldImpl.class, IconLoader.getIcon(path + "F.png"))
             .build();
   }