Fix underscore handling in octal literals

The octal radix check needs to accept e.g. `0_10`, while still excluding
`0` and `0L`.

MOE_MIGRATED_REVID=139086201
diff --git a/java/com/google/turbine/parse/ConstExpressionParser.java b/java/com/google/turbine/parse/ConstExpressionParser.java
index 3c89ffe..4a3b297 100644
--- a/java/com/google/turbine/parse/ConstExpressionParser.java
+++ b/java/com/google/turbine/parse/ConstExpressionParser.java
@@ -286,9 +286,7 @@
           if (text.startsWith("0x") || text.startsWith("0X")) {
             text = text.substring(2);
             radix = 0x10;
-          } else if (text.startsWith("0")
-              && text.length() > 1
-              && Character.isDigit(text.charAt(1))) {
+          } else if (isOctal(text)) {
             radix = 010;
           } else if (text.startsWith("0b") || text.startsWith("0B")) {
             text = text.substring(2);
@@ -316,9 +314,7 @@
           if (text.startsWith("0x") || text.startsWith("0X")) {
             text = text.substring(2);
             radix = 0x10;
-          } else if (text.startsWith("0")
-              && text.length() > 1
-              && Character.isDigit(text.charAt(1))) {
+          } else if (isOctal(text)) {
             radix = 010;
           } else if (text.startsWith("0b") || text.startsWith("0B")) {
             text = text.substring(2);
@@ -360,6 +356,17 @@
     return new Tree.Literal(position, kind, value);
   }
 
+  static boolean isOctal(String text) {
+    if (!text.startsWith("0")) {
+      return false;
+    }
+    if (text.length() <= 1) {
+      return false;
+    }
+    char next = text.charAt(1);
+    return Character.isDigit(next) || next == '_';
+  }
+
   /**
    * Parse the string as a signed long.
    *
diff --git a/javatests/com/google/turbine/lower/LowerIntegrationTest.java b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
index fd332b3..c1859e5 100644
--- a/javatests/com/google/turbine/lower/LowerIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
@@ -266,6 +266,7 @@
       "deficient_types_classfile.test",
       "ctor_anno.test",
       "anno_const_coerce.test",
+      "const_octal_underscore.test",
     };
     List<Object[]> tests =
         ImmutableList.copyOf(testCases).stream().map(x -> new Object[] {x}).collect(toList());
diff --git a/javatests/com/google/turbine/lower/testdata/const_octal_underscore.test b/javatests/com/google/turbine/lower/testdata/const_octal_underscore.test
new file mode 100644
index 0000000..142edd7
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/const_octal_underscore.test
@@ -0,0 +1,6 @@
+=== Test.java ===
+class Test {
+  static final int A = 0_10;
+  static final long B = 0_10;
+  static final long C = 0_10L;
+}
\ No newline at end of file