1 /* 2 * Copyright 2016 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.turbine.parse; 18 19 import static com.google.common.collect.Iterables.getOnlyElement; 20 21 import com.google.common.collect.ImmutableList; 22 import com.google.errorprone.annotations.CheckReturnValue; 23 import com.google.turbine.diag.TurbineError; 24 import com.google.turbine.diag.TurbineError.ErrorKind; 25 import com.google.turbine.model.Const; 26 import com.google.turbine.model.TurbineConstantTypeKind; 27 import com.google.turbine.tree.Tree; 28 import com.google.turbine.tree.Tree.ClassLiteral; 29 import com.google.turbine.tree.Tree.ClassTy; 30 import com.google.turbine.tree.Tree.Expression; 31 import com.google.turbine.tree.Tree.Ident; 32 import com.google.turbine.tree.TurbineOperatorKind; 33 import java.util.Optional; 34 import org.checkerframework.checker.nullness.qual.Nullable; 35 36 /** A parser for compile-time constant expressions. */ 37 public class ConstExpressionParser { 38 39 Token token; 40 private int position; 41 private final Lexer lexer; 42 ConstExpressionParser(Lexer lexer, Token token)43 public ConstExpressionParser(Lexer lexer, Token token) { 44 this.lexer = lexer; 45 this.token = token; 46 this.position = lexer.position(); 47 } 48 operator(Token token)49 private static TurbineOperatorKind operator(Token token) { 50 switch (token) { 51 case ASSIGN: 52 // TODO(cushon): only allow in annotations? 53 return TurbineOperatorKind.ASSIGN; 54 case MULT: 55 return TurbineOperatorKind.MULT; 56 case DIV: 57 return TurbineOperatorKind.DIVIDE; 58 case MOD: 59 return TurbineOperatorKind.MODULO; 60 case PLUS: 61 return TurbineOperatorKind.PLUS; 62 case MINUS: 63 return TurbineOperatorKind.MINUS; 64 case LTLT: 65 return TurbineOperatorKind.SHIFT_LEFT; 66 case GTGT: 67 return TurbineOperatorKind.SHIFT_RIGHT; 68 case GTGTGT: 69 return TurbineOperatorKind.UNSIGNED_SHIFT_RIGHT; 70 case LT: 71 return TurbineOperatorKind.LESS_THAN; 72 case GT: 73 return TurbineOperatorKind.GREATER_THAN; 74 case LTE: 75 return TurbineOperatorKind.LESS_THAN_EQ; 76 case GTE: 77 return TurbineOperatorKind.GREATER_THAN_EQ; 78 case EQ: 79 return TurbineOperatorKind.EQUAL; 80 case NOTEQ: 81 return TurbineOperatorKind.NOT_EQUAL; 82 case AND: 83 return TurbineOperatorKind.BITWISE_AND; 84 case OR: 85 return TurbineOperatorKind.BITWISE_OR; 86 case XOR: 87 return TurbineOperatorKind.BITWISE_XOR; 88 case ANDAND: 89 return TurbineOperatorKind.AND; 90 case OROR: 91 return TurbineOperatorKind.OR; 92 case COND: 93 return TurbineOperatorKind.TERNARY; 94 default: 95 return null; 96 } 97 } 98 primary(boolean negate)99 private Tree.@Nullable Expression primary(boolean negate) { 100 switch (token) { 101 case INT_LITERAL: 102 return finishLiteral(TurbineConstantTypeKind.INT, negate); 103 case DOUBLE_LITERAL: 104 return finishLiteral(TurbineConstantTypeKind.DOUBLE, negate); 105 case LONG_LITERAL: 106 return finishLiteral(TurbineConstantTypeKind.LONG, negate); 107 case FLOAT_LITERAL: 108 return finishLiteral(TurbineConstantTypeKind.FLOAT, negate); 109 case TRUE: 110 eat(); 111 return new Tree.Literal( 112 position, TurbineConstantTypeKind.BOOLEAN, new Const.BooleanValue(true)); 113 case FALSE: 114 eat(); 115 return new Tree.Literal( 116 position, TurbineConstantTypeKind.BOOLEAN, new Const.BooleanValue(false)); 117 case CHAR_LITERAL: 118 return finishLiteral(TurbineConstantTypeKind.CHAR, negate); 119 case STRING_LITERAL: 120 return finishLiteral(TurbineConstantTypeKind.STRING, false); 121 case PLUS: 122 eat(); 123 return unaryRest(TurbineOperatorKind.UNARY_PLUS); 124 case MINUS: 125 eat(); 126 return unaryRest(TurbineOperatorKind.NEG); 127 case NOT: 128 eat(); 129 return unaryRest(TurbineOperatorKind.NOT); 130 case TILDE: 131 eat(); 132 return unaryRest(TurbineOperatorKind.BITWISE_COMP); 133 case LPAREN: 134 return maybeCast(); 135 case LBRACE: 136 int pos = position; 137 eat(); 138 return arrayInitializer(pos); 139 case IDENT: 140 return qualIdent(); 141 case BYTE: 142 return primitiveClassLiteral(TurbineConstantTypeKind.BYTE); 143 case CHAR: 144 return primitiveClassLiteral(TurbineConstantTypeKind.CHAR); 145 case DOUBLE: 146 return primitiveClassLiteral(TurbineConstantTypeKind.DOUBLE); 147 case FLOAT: 148 return primitiveClassLiteral(TurbineConstantTypeKind.FLOAT); 149 case INT: 150 return primitiveClassLiteral(TurbineConstantTypeKind.INT); 151 case LONG: 152 return primitiveClassLiteral(TurbineConstantTypeKind.LONG); 153 case SHORT: 154 return primitiveClassLiteral(TurbineConstantTypeKind.SHORT); 155 case BOOLEAN: 156 return primitiveClassLiteral(TurbineConstantTypeKind.BOOLEAN); 157 case VOID: 158 eat(); 159 return finishClassLiteral(position, new Tree.VoidTy(position)); 160 case AT: 161 return annotation(); 162 default: 163 return null; 164 } 165 } 166 primitiveClassLiteral(TurbineConstantTypeKind type)167 private Expression primitiveClassLiteral(TurbineConstantTypeKind type) { 168 eat(); 169 return finishClassLiteral(position, new Tree.PrimTy(position, ImmutableList.of(), type)); 170 } 171 maybeCast()172 private Tree.Expression maybeCast() { 173 eat(); 174 switch (token) { 175 case BOOLEAN: 176 eat(); 177 return castTail(TurbineConstantTypeKind.BOOLEAN); 178 case BYTE: 179 eat(); 180 return castTail(TurbineConstantTypeKind.BYTE); 181 case SHORT: 182 eat(); 183 return castTail(TurbineConstantTypeKind.SHORT); 184 case INT: 185 eat(); 186 return castTail(TurbineConstantTypeKind.INT); 187 case LONG: 188 eat(); 189 return castTail(TurbineConstantTypeKind.LONG); 190 case CHAR: 191 eat(); 192 return castTail(TurbineConstantTypeKind.CHAR); 193 case DOUBLE: 194 eat(); 195 return castTail(TurbineConstantTypeKind.DOUBLE); 196 case FLOAT: 197 eat(); 198 return castTail(TurbineConstantTypeKind.FLOAT); 199 default: 200 return notCast(); 201 } 202 } 203 notCast()204 private Tree.Expression notCast() { 205 Tree.Expression expr = expression(null); 206 if (expr == null) { 207 return null; 208 } 209 if (token != Token.RPAREN) { 210 return null; 211 } 212 eat(); 213 if (expr.kind() == Tree.Kind.CONST_VAR_NAME) { 214 Tree.ConstVarName cvar = (Tree.ConstVarName) expr; 215 switch (token) { 216 case INT_LITERAL: 217 case FLOAT_LITERAL: 218 case TRUE: 219 case FALSE: 220 case CHAR_LITERAL: 221 case STRING_LITERAL: 222 case NOT: 223 case TILDE: 224 case IDENT: 225 return new Tree.TypeCast( 226 position, asClassTy(cvar.position(), cvar.name()), primary(false)); 227 default: 228 return expr; 229 } 230 } else { 231 return expr; 232 } 233 } 234 asClassTy(int pos, ImmutableList<Tree.Ident> names)235 private static ClassTy asClassTy(int pos, ImmutableList<Tree.Ident> names) { 236 ClassTy cty = null; 237 for (Tree.Ident bit : names) { 238 cty = new ClassTy(pos, Optional.ofNullable(cty), bit, ImmutableList.of(), ImmutableList.of()); 239 } 240 return cty; 241 } 242 eat()243 private void eat() { 244 token = lexer.next(); 245 position = lexer.position(); 246 } 247 arrayInitializer(int pos)248 private Tree.Expression arrayInitializer(int pos) { 249 if (token == Token.RBRACE) { 250 eat(); 251 return new Tree.ArrayInit(pos, ImmutableList.<Tree.Expression>of()); 252 } 253 254 ImmutableList.Builder<Tree.Expression> exprs = ImmutableList.builder(); 255 OUTER: 256 while (true) { 257 if (token == Token.RBRACE) { 258 eat(); 259 break OUTER; 260 } 261 Tree.Expression item = expression(null); 262 if (item == null) { 263 return null; 264 } 265 exprs.add(item); 266 switch (token) { 267 case COMMA: 268 eat(); 269 break; 270 case RBRACE: 271 eat(); 272 break OUTER; 273 default: 274 return null; 275 } 276 } 277 return new Tree.ArrayInit(pos, exprs.build()); 278 } 279 280 /** Finish hex, decimal, octal, and binary integer literals (see JLS 3.10.1). */ finishLiteral(TurbineConstantTypeKind kind, boolean negate)281 private Tree.Expression finishLiteral(TurbineConstantTypeKind kind, boolean negate) { 282 int pos = position; 283 String text = ident().value(); 284 Const.Value value; 285 switch (kind) { 286 case INT: 287 { 288 int radix = 10; 289 if (text.startsWith("0x") || text.startsWith("0X")) { 290 text = text.substring(2); 291 radix = 0x10; 292 } else if (isOctal(text)) { 293 radix = 010; 294 } else if (text.startsWith("0b") || text.startsWith("0B")) { 295 text = text.substring(2); 296 radix = 0b10; 297 } 298 if (negate) { 299 text = "-" + text; 300 } 301 long longValue = parseLong(text, radix); 302 if (radix == 10) { 303 if (longValue != (int) longValue) { 304 throw error(ErrorKind.INVALID_LITERAL, text); 305 } 306 } else { 307 if (Math.abs(longValue) >> 32 != 0) { 308 throw error(ErrorKind.INVALID_LITERAL, text); 309 } 310 } 311 value = new Const.IntValue((int) longValue); 312 break; 313 } 314 case LONG: 315 { 316 int radix = 10; 317 if (text.startsWith("0x") || text.startsWith("0X")) { 318 text = text.substring(2); 319 radix = 0x10; 320 } else if (isOctal(text)) { 321 radix = 010; 322 } else if (text.startsWith("0b") || text.startsWith("0B")) { 323 text = text.substring(2); 324 radix = 0b10; 325 } 326 if (negate) { 327 text = "-" + text; 328 } 329 if (text.endsWith("L") || text.endsWith("l")) { 330 text = text.substring(0, text.length() - 1); 331 } 332 value = new Const.LongValue(parseLong(text, radix)); 333 break; 334 } 335 case CHAR: 336 value = new Const.CharValue(text.charAt(0)); 337 break; 338 case FLOAT: 339 try { 340 value = new Const.FloatValue(Float.parseFloat(text.replace("_", ""))); 341 } catch (NumberFormatException e) { 342 throw error(ErrorKind.INVALID_LITERAL, text); 343 } 344 break; 345 case DOUBLE: 346 try { 347 value = new Const.DoubleValue(Double.parseDouble(text.replace("_", ""))); 348 } catch (NumberFormatException e) { 349 throw error(ErrorKind.INVALID_LITERAL, text); 350 } 351 break; 352 case STRING: 353 value = new Const.StringValue(text); 354 break; 355 default: 356 throw new AssertionError(kind); 357 } 358 eat(); 359 return new Tree.Literal(pos, kind, value); 360 } 361 isOctal(String text)362 static boolean isOctal(String text) { 363 if (!text.startsWith("0")) { 364 return false; 365 } 366 if (text.length() <= 1) { 367 return false; 368 } 369 char next = text.charAt(1); 370 return Character.isDigit(next) || next == '_'; 371 } 372 373 /** 374 * Parse the string as a signed long. 375 * 376 * <p>{@link Long#parseLong} doesn't accept {@link Long#MIN_VALUE}. 377 */ parseLong(String text, int radix)378 private long parseLong(String text, int radix) { 379 long r = 0; 380 boolean neg = text.startsWith("-"); 381 if (neg) { 382 text = text.substring(1); 383 } 384 for (char c : text.toCharArray()) { 385 int digit; 386 if ('0' <= c && c <= '9') { 387 digit = c - '0'; 388 } else if ('a' <= c && c <= 'f') { 389 digit = 10 + (c - 'a'); 390 } else if ('A' <= c && c <= 'F') { 391 digit = 10 + (c - 'A'); 392 } else if (c == '_') { 393 continue; 394 } else { 395 throw error(ErrorKind.INVALID_LITERAL, text); 396 } 397 r = (r * radix) + digit; 398 } 399 if (neg) { 400 r = -r; 401 } 402 return r; 403 } 404 unaryRest(TurbineOperatorKind op)405 private Tree.Expression unaryRest(TurbineOperatorKind op) { 406 boolean negate = op == TurbineOperatorKind.NEG; 407 Tree.Expression expr = primary(negate); 408 if (expr == null) { 409 return null; 410 } 411 if (negate && expr.kind() == Tree.Kind.LITERAL) { 412 Tree.Literal lit = (Tree.Literal) expr; 413 switch (lit.tykind()) { 414 case INT: 415 case LONG: 416 return expr; 417 default: 418 break; 419 } 420 } 421 return new Tree.Unary(position, expr, op); 422 } 423 qualIdent()424 private Tree.@Nullable Expression qualIdent() { 425 int pos = position; 426 ImmutableList.Builder<Ident> bits = ImmutableList.builder(); 427 bits.add(ident()); 428 eat(); 429 if (token == Token.LBRACK) { 430 return finishClassLiteral(pos, asClassTy(pos, bits.build())); 431 } 432 while (token == Token.DOT) { 433 eat(); 434 switch (token) { 435 case IDENT: 436 bits.add(ident()); 437 break; 438 case CLASS: 439 // TODO(cushon): only allow in annotations? 440 eat(); 441 return new Tree.ClassLiteral(pos, asClassTy(pos, bits.build())); 442 default: 443 return null; 444 } 445 eat(); 446 } 447 return new Tree.ConstVarName(pos, bits.build()); 448 } 449 ident()450 private Ident ident() { 451 return new Ident(lexer.position(), lexer.stringValue()); 452 } 453 finishClassLiteral(int pos, Tree.Type type)454 private Expression finishClassLiteral(int pos, Tree.Type type) { 455 while (token == Token.LBRACK) { 456 eat(); 457 if (token != Token.RBRACK) { 458 return null; 459 } 460 eat(); 461 type = new Tree.ArrTy(position, ImmutableList.of(), type); 462 } 463 if (token != Token.DOT) { 464 return null; 465 } 466 eat(); 467 if (token != Token.CLASS) { 468 return null; 469 } 470 eat(); 471 return new ClassLiteral(pos, type); 472 } 473 expression()474 public Tree.Expression expression() { 475 Tree.Expression result = expression(null); 476 switch (token) { 477 case EOF: 478 case SEMI: 479 // TODO(cushon): only allow in annotations? 480 case COMMA: 481 case RPAREN: 482 return result; 483 default: 484 return null; 485 } 486 } 487 expression(TurbineOperatorKind.Precedence prec)488 private Tree.Expression expression(TurbineOperatorKind.Precedence prec) { 489 Tree.Expression term1 = primary(false); 490 if (term1 == null) { 491 return null; 492 } 493 return expression(term1, prec); 494 } 495 expression(Tree.Expression term1, TurbineOperatorKind.Precedence prec)496 private Tree.Expression expression(Tree.Expression term1, TurbineOperatorKind.Precedence prec) { 497 while (true) { 498 if (token == Token.EOF) { 499 return term1; 500 } 501 TurbineOperatorKind op = operator(token); 502 if (op == null) { 503 return term1; 504 } 505 if (prec != null && op.prec().rank() <= prec.rank()) { 506 return term1; 507 } 508 eat(); 509 if (op == TurbineOperatorKind.TERNARY) { 510 term1 = ternary(term1); 511 } else if (op == TurbineOperatorKind.ASSIGN) { 512 term1 = assign(term1, op); 513 } else { 514 term1 = new Tree.Binary(position, term1, expression(op.prec()), op); 515 } 516 if (term1 == null) { 517 return null; 518 } 519 } 520 } 521 assign(Tree.Expression term1, TurbineOperatorKind op)522 private Tree.Expression assign(Tree.Expression term1, TurbineOperatorKind op) { 523 if (!(term1 instanceof Tree.ConstVarName)) { 524 return null; 525 } 526 ImmutableList<Ident> names = ((Tree.ConstVarName) term1).name(); 527 if (names.size() > 1) { 528 return null; 529 } 530 Ident name = getOnlyElement(names); 531 Tree.Expression rhs = expression(op.prec()); 532 if (rhs == null) { 533 return null; 534 } 535 return new Tree.Assign(term1.position(), name, rhs); 536 } 537 ternary(Tree.Expression term1)538 private Tree.Expression ternary(Tree.Expression term1) { 539 Tree.Expression thenExpr = expression(TurbineOperatorKind.Precedence.TERNARY); 540 if (thenExpr == null) { 541 return null; 542 } 543 if (token != Token.COLON) { 544 return null; 545 } 546 eat(); 547 Tree.Expression elseExpr = expression(); 548 if (elseExpr == null) { 549 return null; 550 } 551 return new Tree.Conditional(position, term1, thenExpr, elseExpr); 552 } 553 castTail(TurbineConstantTypeKind ty)554 private Tree.Expression castTail(TurbineConstantTypeKind ty) { 555 if (token != Token.RPAREN) { 556 return null; 557 } 558 eat(); 559 Tree.Expression rhs = primary(false); 560 if (rhs == null) { 561 return null; 562 } 563 return new Tree.TypeCast(position, new Tree.PrimTy(position, ImmutableList.of(), ty), rhs); 564 } 565 annotation()566 private Tree.@Nullable AnnoExpr annotation() { 567 if (token != Token.AT) { 568 throw new AssertionError(); 569 } 570 eat(); 571 Tree.ConstVarName constVarName = (Tree.ConstVarName) qualIdent(); 572 if (constVarName == null) { 573 return null; 574 } 575 ImmutableList<Ident> name = constVarName.name(); 576 ImmutableList.Builder<Tree.Expression> args = ImmutableList.builder(); 577 if (token == Token.LPAREN) { 578 eat(); 579 while (token != Token.RPAREN) { 580 int pos = position; 581 Tree.Expression expression = expression(); 582 if (expression == null) { 583 throw TurbineError.format(lexer.source(), pos, ErrorKind.INVALID_ANNOTATION_ARGUMENT); 584 } 585 args.add(expression); 586 if (token != Token.COMMA) { 587 break; 588 } 589 eat(); 590 } 591 if (token == Token.RPAREN) { 592 eat(); 593 } 594 } 595 return new Tree.AnnoExpr(position, new Tree.Anno(position, name, args.build())); 596 } 597 598 @CheckReturnValue error(ErrorKind kind, Object... args)599 private TurbineError error(ErrorKind kind, Object... args) { 600 return TurbineError.format(lexer.source(), lexer.position(), kind, args); 601 } 602 } 603