aboutsummaryrefslogtreecommitdiff
path: root/java/com/google/turbine/parse
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/turbine/parse')
-rw-r--r--java/com/google/turbine/parse/ConstExpressionParser.java53
-rw-r--r--java/com/google/turbine/parse/IteratorLexer.java13
-rw-r--r--java/com/google/turbine/parse/Lexer.java5
-rw-r--r--java/com/google/turbine/parse/ParseError.java33
-rw-r--r--java/com/google/turbine/parse/Parser.java107
-rw-r--r--java/com/google/turbine/parse/StreamLexer.java48
-rw-r--r--java/com/google/turbine/parse/UnicodeEscapePreprocessor.java17
7 files changed, 152 insertions, 124 deletions
diff --git a/java/com/google/turbine/parse/ConstExpressionParser.java b/java/com/google/turbine/parse/ConstExpressionParser.java
index c3e4e88..7749b71 100644
--- a/java/com/google/turbine/parse/ConstExpressionParser.java
+++ b/java/com/google/turbine/parse/ConstExpressionParser.java
@@ -21,13 +21,13 @@ import static com.google.common.collect.Iterables.getOnlyElement;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;
+import com.google.turbine.diag.TurbineError;
import com.google.turbine.model.Const;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.ClassLiteral;
import com.google.turbine.tree.Tree.ClassTy;
import com.google.turbine.tree.Tree.Expression;
-import com.google.turbine.tree.Tree.VoidTy;
import com.google.turbine.tree.TurbineOperatorKind;
import javax.annotation.Nullable;
@@ -35,11 +35,12 @@ import javax.annotation.Nullable;
public class ConstExpressionParser {
Token token;
+ private int position;
private final Lexer lexer;
public ConstExpressionParser(Lexer lexer) {
this.lexer = lexer;
- token = lexer.next();
+ eat();
}
private static TurbineOperatorKind operator(Token token) {
@@ -104,10 +105,12 @@ public class ConstExpressionParser {
return finishLiteral(TurbineConstantTypeKind.FLOAT, negate);
case TRUE:
eat();
- return new Tree.Literal(TurbineConstantTypeKind.BOOLEAN, new Const.BooleanValue(true));
+ return new Tree.Literal(
+ position, TurbineConstantTypeKind.BOOLEAN, new Const.BooleanValue(true));
case FALSE:
eat();
- return new Tree.Literal(TurbineConstantTypeKind.BOOLEAN, new Const.BooleanValue(false));
+ return new Tree.Literal(
+ position, TurbineConstantTypeKind.BOOLEAN, new Const.BooleanValue(false));
case CHAR_LITERAL:
return finishLiteral(TurbineConstantTypeKind.CHAR, negate);
case STRING_LITERAL:
@@ -148,7 +151,7 @@ public class ConstExpressionParser {
case BOOLEAN:
return primitiveClassLiteral(TurbineConstantTypeKind.BOOLEAN);
case VOID:
- return primitiveClassLiteral(VoidTy.INSTANCE);
+ return primitiveClassLiteral(new Tree.VoidTy(position));
case AT:
return annotation();
default:
@@ -157,7 +160,7 @@ public class ConstExpressionParser {
}
private Expression primitiveClassLiteral(TurbineConstantTypeKind type) {
- return primitiveClassLiteral(new Tree.PrimTy(type));
+ return primitiveClassLiteral(new Tree.PrimTy(position, type));
}
private Expression primitiveClassLiteral(Tree.Type type) {
@@ -170,7 +173,7 @@ public class ConstExpressionParser {
return null;
}
eat();
- return new ClassLiteral(type);
+ return new ClassLiteral(position, type);
}
private Tree.Expression maybeCast() {
@@ -226,9 +229,7 @@ public class ConstExpressionParser {
case NOT:
case TILDE:
case IDENT:
- {
- return new Tree.TypeCast(asClassTy(cvar.name()), primary(false));
- }
+ return new Tree.TypeCast(position, asClassTy(cvar.name()), primary(false));
default:
return expr;
}
@@ -240,19 +241,20 @@ public class ConstExpressionParser {
private ClassTy asClassTy(ImmutableList<String> names) {
ClassTy cty = null;
for (String bit : names) {
- cty = new ClassTy(Optional.fromNullable(cty), bit, ImmutableList.<Tree.Type>of());
+ cty = new ClassTy(position, Optional.fromNullable(cty), bit, ImmutableList.<Tree.Type>of());
}
return cty;
}
private void eat() {
token = lexer.next();
+ position = lexer.position();
}
private Tree.Expression arrayInitializer() {
if (token == Token.RBRACE) {
eat();
- return new Tree.ArrayInit(ImmutableList.<Tree.Expression>of());
+ return new Tree.ArrayInit(position, ImmutableList.<Tree.Expression>of());
}
ImmutableList.Builder<Tree.Expression> exprs = ImmutableList.builder();
@@ -278,7 +280,7 @@ public class ConstExpressionParser {
return null;
}
}
- return new Tree.ArrayInit(exprs.build());
+ return new Tree.ArrayInit(position, exprs.build());
}
/** Finish hex, decimal, octal, and binary integer literals (see JLS 3.10.1). */
@@ -345,10 +347,10 @@ public class ConstExpressionParser {
value = new Const.StringValue(text);
break;
default:
- throw error(kind);
+ throw error("%s", kind);
}
eat();
- return new Tree.Literal(kind, value);
+ return new Tree.Literal(position, kind, value);
}
/**
@@ -399,11 +401,12 @@ public class ConstExpressionParser {
if (expr == null) {
return null;
}
- return new Tree.Unary(expr, op);
+ return new Tree.Unary(position, expr, op);
}
@Nullable
private Tree.Expression qualIdent() {
+ int pos = position;
ImmutableList.Builder<String> bits = ImmutableList.builder();
bits.add(lexer.stringValue());
eat();
@@ -416,13 +419,13 @@ public class ConstExpressionParser {
case CLASS:
// TODO(cushon): only allow in annotations?
eat();
- return new Tree.ClassLiteral(asClassTy(bits.build()));
+ return new Tree.ClassLiteral(pos, asClassTy(bits.build()));
default:
return null;
}
eat();
}
- return new Tree.ConstVarName(bits.build());
+ return new Tree.ConstVarName(pos, bits.build());
}
public Tree.Expression expression() {
@@ -465,7 +468,7 @@ public class ConstExpressionParser {
} else if (op == TurbineOperatorKind.ASSIGN) {
term1 = assign(term1, op);
} else {
- term1 = new Tree.Binary(term1, expression(op.prec()), op);
+ term1 = new Tree.Binary(position, term1, expression(op.prec()), op);
}
if (term1 == null) {
return null;
@@ -483,7 +486,7 @@ public class ConstExpressionParser {
}
String name = getOnlyElement(names);
Tree.Expression rhs = expression(op.prec());
- return new Tree.Assign(name, rhs);
+ return new Tree.Assign(term1.position(), name, rhs);
}
private Tree.Expression ternary(Tree.Expression term1) {
@@ -499,7 +502,7 @@ public class ConstExpressionParser {
if (elseExpr == null) {
return null;
}
- return new Tree.Conditional(term1, thenExpr, elseExpr);
+ return new Tree.Conditional(position, term1, thenExpr, elseExpr);
}
private Tree.Expression castTail(TurbineConstantTypeKind ty) {
@@ -511,7 +514,7 @@ public class ConstExpressionParser {
if (rhs == null) {
throw new AssertionError();
}
- return new Tree.TypeCast(new Tree.PrimTy(ty), rhs);
+ return new Tree.TypeCast(position, new Tree.PrimTy(position, ty), rhs);
}
private Tree.AnnoExpr annotation() {
@@ -539,10 +542,10 @@ public class ConstExpressionParser {
eat();
}
}
- return new Tree.AnnoExpr(new Tree.Anno(name, args.build()));
+ return new Tree.AnnoExpr(position, new Tree.Anno(position, name, args.build()));
}
- private ParseError error(Object message) {
- return new ParseError(lexer.position(), String.valueOf(message));
+ private TurbineError error(String message, Object... args) {
+ return TurbineError.format(lexer.source(), lexer.position(), message, args);
}
}
diff --git a/java/com/google/turbine/parse/IteratorLexer.java b/java/com/google/turbine/parse/IteratorLexer.java
index 04b8ab4..823f9bb 100644
--- a/java/com/google/turbine/parse/IteratorLexer.java
+++ b/java/com/google/turbine/parse/IteratorLexer.java
@@ -16,6 +16,7 @@
package com.google.turbine.parse;
+import com.google.turbine.diag.SourceFile;
import java.util.Iterator;
/**
@@ -25,14 +26,21 @@ import java.util.Iterator;
*/
public class IteratorLexer implements Lexer {
+ private final SourceFile source;
private final Iterator<SavedToken> it;
private SavedToken curr;
- public IteratorLexer(Iterator<SavedToken> it) {
+ public IteratorLexer(SourceFile source, Iterator<SavedToken> it) {
+ this.source = source;
this.it = it;
}
@Override
+ public SourceFile source() {
+ return source;
+ }
+
+ @Override
public Token next() {
if (it.hasNext()) {
curr = it.next();
@@ -48,6 +56,7 @@ public class IteratorLexer implements Lexer {
@Override
public int position() {
- return curr.position;
+ // TODO(cushon): test expression position EOF handling
+ return curr != null ? curr.position : -1;
}
}
diff --git a/java/com/google/turbine/parse/Lexer.java b/java/com/google/turbine/parse/Lexer.java
index 58b092f..2d8422a 100644
--- a/java/com/google/turbine/parse/Lexer.java
+++ b/java/com/google/turbine/parse/Lexer.java
@@ -16,6 +16,8 @@
package com.google.turbine.parse;
+import com.google.turbine.diag.SourceFile;
+
/** A Java lexer. */
public interface Lexer {
/** Returns the next token in the input stream, or {@code EOF}. */
@@ -26,4 +28,7 @@ public interface Lexer {
/** Returns the current position in the input. */
int position();
+
+ /** Returns the source file for diagnostics. */
+ SourceFile source();
}
diff --git a/java/com/google/turbine/parse/ParseError.java b/java/com/google/turbine/parse/ParseError.java
deleted file mode 100644
index f3cc8fb..0000000
--- a/java/com/google/turbine/parse/ParseError.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.turbine.parse;
-
-/** A parse error. */
-public class ParseError extends Error {
- private final int position;
-
- /** @param position the character offset of the parser error. */
- public ParseError(int position, String message) {
- super(message);
- this.position = position;
- }
-
- /** Returns the UTF-16 code unit offset of the error. */
- public int position() {
- return position;
- }
-}
diff --git a/java/com/google/turbine/parse/Parser.java b/java/com/google/turbine/parse/Parser.java
index 9025ef7..83d5e34 100644
--- a/java/com/google/turbine/parse/Parser.java
+++ b/java/com/google/turbine/parse/Parser.java
@@ -23,6 +23,8 @@ import static com.google.turbine.tree.TurbineModifier.PUBLIC;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.turbine.diag.SourceFile;
+import com.google.turbine.diag.TurbineError;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.model.TurbineTyKind;
import com.google.turbine.tree.Tree;
@@ -56,9 +58,14 @@ public class Parser {
private final Lexer lexer;
private Token token;
+ private int position;
- public static CompUnit parse(String input) {
- return new Parser(new StreamLexer(new UnicodeEscapePreprocessor(input))).compilationUnit();
+ public static CompUnit parse(String source) {
+ return parse(new SourceFile(null, source));
+ }
+
+ public static CompUnit parse(SourceFile source) {
+ return new Parser(new StreamLexer(new UnicodeEscapePreprocessor(source))).compilationUnit();
}
private Parser(Lexer lexer) {
@@ -150,7 +157,7 @@ public class Parser {
break;
case EOF:
// TODO(cushon): check for dangling modifiers?
- return new CompUnit(pkg, imports.build(), decls.build(), null);
+ return new CompUnit(position, pkg, imports.build(), decls.build(), lexer.source());
case SEMI:
// TODO(cushon): check for dangling modifiers?
next();
@@ -163,6 +170,7 @@ public class Parser {
private void next() {
token = lexer.next();
+ position = lexer.position();
}
private TyDecl interfaceDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
@@ -185,6 +193,7 @@ public class Parser {
ImmutableList<Tree> members = classMembers();
eat(Token.RBRACE);
return new TyDecl(
+ position,
access,
annos,
name,
@@ -202,6 +211,7 @@ public class Parser {
ImmutableList<Tree> members = classMembers();
eat(Token.RBRACE);
return new TyDecl(
+ position,
access,
annos,
name,
@@ -227,6 +237,7 @@ public class Parser {
ImmutableList.<Tree>builder().addAll(enumMembers(name)).addAll(classMembers()).build();
eat(Token.RBRACE);
return new TyDecl(
+ position,
access,
annos,
name,
@@ -265,9 +276,11 @@ public class Parser {
maybe(Token.COMMA);
result.add(
new VarDecl(
+ position,
access,
annos.build(),
- new ClassTy(Optional.<ClassTy>absent(), enumName, ImmutableList.<Type>of()),
+ new ClassTy(
+ position, Optional.<ClassTy>absent(), enumName, ImmutableList.<Type>of()),
name,
Optional.<Expression>absent()));
annos = ImmutableList.builder();
@@ -314,6 +327,7 @@ public class Parser {
ImmutableList<Tree> members = classMembers();
eat(Token.RBRACE);
return new TyDecl(
+ position,
access,
annos,
name,
@@ -451,7 +465,7 @@ public class Parser {
switch (token) {
case VOID:
{
- result = Tree.VoidTy.INSTANCE;
+ result = new Tree.VoidTy(position);
next();
name = eatIdent();
return memberRest(access, annos, typaram, result, name);
@@ -480,7 +494,9 @@ public class Parser {
}
case IDENT:
{
- result = new ClassTy(Optional.<ClassTy>absent(), ident, ImmutableList.<Type>of());
+ result =
+ new ClassTy(
+ position, Optional.<ClassTy>absent(), ident, ImmutableList.<Type>of());
name = eatIdent();
return memberRest(access, annos, typaram, result, name);
}
@@ -494,26 +510,30 @@ public class Parser {
} while (maybe(Token.LBRACK));
result =
new ArrTy(
- new ClassTy(Optional.<ClassTy>absent(), ident, ImmutableList.<Type>of()),
+ position,
+ new ClassTy(
+ position, Optional.<ClassTy>absent(), ident, ImmutableList.<Type>of()),
dim);
break;
}
case LT:
{
- Type ty = new ClassTy(Optional.<ClassTy>absent(), ident, tyargs());
+ Type ty = new ClassTy(position, Optional.<ClassTy>absent(), ident, tyargs());
int dim = 0;
while (maybe(Token.LBRACK)) {
eat(Token.RBRACK);
dim++;
}
if (dim > 0) {
- ty = new ArrTy(ty, dim);
+ ty = new ArrTy(position, ty, dim);
}
result = ty;
break;
}
case DOT:
- result = new ClassTy(Optional.<ClassTy>absent(), ident, ImmutableList.<Type>of());
+ result =
+ new ClassTy(
+ position, Optional.<ClassTy>absent(), ident, ImmutableList.<Type>of());
break;
default:
throw error(token);
@@ -531,7 +551,7 @@ public class Parser {
dim++;
}
if (dim > 0) {
- result = new ArrTy(result, dim);
+ result = new ArrTy(position, result, dim);
}
}
name = eatIdent();
@@ -544,7 +564,7 @@ public class Parser {
case COMMA:
{
if (!typaram.isEmpty()) {
- throw error(typaram);
+ throw error("%s", typaram);
}
return fieldRest(access, annos, result, name);
}
@@ -570,7 +590,7 @@ public class Parser {
case COMMA:
{
if (!typaram.isEmpty()) {
- throw error(typaram);
+ throw error("%s", typaram);
}
return fieldRest(access, annos, result, name);
}
@@ -600,7 +620,7 @@ public class Parser {
if (next.token == Token.IDENT) {
name = next.value;
} else {
- throw error(next);
+ throw error("%s", next);
}
}
@@ -613,7 +633,7 @@ public class Parser {
dim++;
next = it.next();
if (next.token != Token.RBRACK) {
- throw error(next);
+ throw error("%s", next);
}
if (it.hasNext()) {
next = it.next();
@@ -622,11 +642,12 @@ public class Parser {
newty = expandDims(ty, dim);
}
// TODO(cushon): skip more fields that are definitely non-const
- Expression init = new ConstExpressionParser(new IteratorLexer(it)).expression();
+ Expression init =
+ new ConstExpressionParser(new IteratorLexer(lexer.source(), it)).expression();
if (init != null && init.kind() == Tree.Kind.ARRAY_INIT) {
init = null;
}
- result.add(new VarDecl(access, annos, newty, name, Optional.fromNullable(init)));
+ result.add(new VarDecl(position, access, annos, newty, name, Optional.fromNullable(init)));
}
eat(Token.SEMI);
return result.build();
@@ -683,6 +704,7 @@ public class Parser {
name = CTOR_NAME;
}
return new MethDecl(
+ position,
access,
annos,
typaram,
@@ -740,15 +762,15 @@ public class Parser {
ty = parseDims(ty);
}
}
- return new VarDecl(access, annos.build(), ty, name, Optional.<Expression>absent());
+ return new VarDecl(position, access, annos.build(), ty, name, Optional.<Expression>absent());
}
private Type expandDims(Type ty, int extra) {
if (ty.kind() == Tree.Kind.ARR_TY) {
Type.ArrTy aty = (Type.ArrTy) ty;
- return new ArrTy(aty.elem(), aty.dim() + extra);
+ return new ArrTy(position, aty.elem(), aty.dim() + extra);
} else if (extra > 0) {
- return new ArrTy(ty, extra);
+ return new ArrTy(position, ty, extra);
} else {
return ty;
}
@@ -801,7 +823,7 @@ public class Parser {
next();
bounds = tybounds();
}
- acc.add(new TyParam(name, bounds));
+ acc.add(new TyParam(position, name, bounds));
switch (token) {
case COMMA:
eat(Token.COMMA);
@@ -829,13 +851,14 @@ public class Parser {
}
private ClassTy classty(ClassTy ty) {
+ int pos = position;
do {
String name = eatIdent();
ImmutableList<Type> tyargs = ImmutableList.of();
if (token == Token.LT) {
tyargs = tyargs();
}
- ty = new ClassTy(Optional.fromNullable(ty), name, tyargs);
+ ty = new ClassTy(pos, Optional.fromNullable(ty), name, tyargs);
} while (maybe(Token.DOT));
return ty;
}
@@ -853,20 +876,20 @@ public class Parser {
case EXTENDS:
next();
Type upper = referenceType();
- acc.add(new WildTy(Optional.of(upper), Optional.<Type>absent()));
+ acc.add(new WildTy(position, Optional.of(upper), Optional.<Type>absent()));
break;
case SUPER:
next();
Type lower = referenceType();
- acc.add(new WildTy(Optional.<Type>absent(), Optional.of(lower)));
+ acc.add(new WildTy(position, Optional.<Type>absent(), Optional.of(lower)));
break;
case COMMA:
- acc.add(new WildTy(Optional.<Type>absent(), Optional.<Type>absent()));
+ acc.add(new WildTy(position, Optional.<Type>absent(), Optional.<Type>absent()));
continue OUTER;
case GT:
case GTGT:
case GTGTGT:
- acc.add(new WildTy(Optional.<Type>absent(), Optional.<Type>absent()));
+ acc.add(new WildTy(position, Optional.<Type>absent(), Optional.<Type>absent()));
break OUTER;
default:
throw error(token);
@@ -912,35 +935,35 @@ public class Parser {
break;
case BOOLEAN:
next();
- ty = new PrimTy(TurbineConstantTypeKind.BOOLEAN);
+ ty = new PrimTy(position, TurbineConstantTypeKind.BOOLEAN);
break;
case BYTE:
next();
- ty = new PrimTy(TurbineConstantTypeKind.BYTE);
+ ty = new PrimTy(position, TurbineConstantTypeKind.BYTE);
break;
case SHORT:
next();
- ty = new PrimTy(TurbineConstantTypeKind.SHORT);
+ ty = new PrimTy(position, TurbineConstantTypeKind.SHORT);
break;
case INT:
next();
- ty = new PrimTy(TurbineConstantTypeKind.INT);
+ ty = new PrimTy(position, TurbineConstantTypeKind.INT);
break;
case LONG:
next();
- ty = new PrimTy(TurbineConstantTypeKind.LONG);
+ ty = new PrimTy(position, TurbineConstantTypeKind.LONG);
break;
case CHAR:
next();
- ty = new PrimTy(TurbineConstantTypeKind.CHAR);
+ ty = new PrimTy(position, TurbineConstantTypeKind.CHAR);
break;
case DOUBLE:
next();
- ty = new PrimTy(TurbineConstantTypeKind.DOUBLE);
+ ty = new PrimTy(position, TurbineConstantTypeKind.DOUBLE);
break;
case FLOAT:
next();
- ty = new PrimTy(TurbineConstantTypeKind.FLOAT);
+ ty = new PrimTy(position, TurbineConstantTypeKind.FLOAT);
break;
default:
throw error(token);
@@ -951,7 +974,7 @@ public class Parser {
dim++;
}
if (dim > 0) {
- ty = new ArrTy(ty, dim);
+ ty = new ArrTy(position, ty, dim);
}
return ty;
}
@@ -1035,11 +1058,11 @@ public class Parser {
}
}
eat(Token.SEMI);
- return new ImportDecl(type.build(), stat, wild);
+ return new ImportDecl(position, type.build(), stat, wild);
}
private PkgDecl packageDeclaration() {
- PkgDecl result = new PkgDecl(qualIdent());
+ PkgDecl result = new PkgDecl(position, qualIdent());
eat(Token.SEMI);
return result;
}
@@ -1066,7 +1089,7 @@ public class Parser {
eat(Token.RPAREN);
}
- return new Anno(name, args.build());
+ return new Anno(position, name, args.build());
}
private String eatIdent() {
@@ -1090,7 +1113,7 @@ public class Parser {
return false;
}
- ParseError error(Token token) {
+ TurbineError error(Token token) {
String message;
switch (token) {
case IDENT:
@@ -1100,10 +1123,10 @@ public class Parser {
message = String.format("unexpected token %s", token);
break;
}
- return new ParseError(lexer.position(), message);
+ return TurbineError.format(lexer.source(), lexer.position(), message, new Object[] {});
}
- private ParseError error(Object message) {
- return new ParseError(lexer.position(), String.valueOf(message));
+ private TurbineError error(String message, Object... args) {
+ return TurbineError.format(lexer.source(), lexer.position(), message, args);
}
}
diff --git a/java/com/google/turbine/parse/StreamLexer.java b/java/com/google/turbine/parse/StreamLexer.java
index cc6d6c2..35dd81d 100644
--- a/java/com/google/turbine/parse/StreamLexer.java
+++ b/java/com/google/turbine/parse/StreamLexer.java
@@ -19,6 +19,8 @@ package com.google.turbine.parse;
import static com.google.turbine.parse.UnicodeEscapePreprocessor.ASCII_SUB;
import com.google.common.base.Verify;
+import com.google.turbine.diag.SourceFile;
+import com.google.turbine.diag.TurbineError;
/** A {@link Lexer} that streams input from a {@link UnicodeEscapePreprocessor}. */
public class StreamLexer implements Lexer {
@@ -28,6 +30,9 @@ public class StreamLexer implements Lexer {
/** The current input character. */
private char ch;
+ /** The start position of the current token. */
+ private int position;
+
/** The start position of the current numeric literal or identifier token. */
private int readFrom;
@@ -65,15 +70,19 @@ public class StreamLexer implements Lexer {
@Override
public int position() {
- // TODO(cushon): this is the position of the character after the last token that was lexed,
- // keep track of start positions instead.
- return reader.position();
+ return position;
+ }
+
+ @Override
+ public SourceFile source() {
+ return reader.source();
}
@Override
public Token next() {
OUTER:
while (true) {
+ position = reader.position();
switch (ch) {
case '\r':
case '\n':
@@ -309,8 +318,7 @@ public class StreamLexer implements Lexer {
eat();
return Token.ELLIPSIS;
} else {
- throw new ParseError(
- reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
}
case '0':
@@ -345,7 +353,7 @@ public class StreamLexer implements Lexer {
eat();
return Token.CHAR_LITERAL;
}
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
case '"':
@@ -379,7 +387,7 @@ public class StreamLexer implements Lexer {
}
// does not fall through
default:
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
}
}
@@ -459,7 +467,7 @@ public class StreamLexer implements Lexer {
}
}
default:
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
}
@@ -566,7 +574,7 @@ public class StreamLexer implements Lexer {
eat();
break;
default:
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
OUTER:
while (true) {
@@ -601,7 +609,7 @@ public class StreamLexer implements Lexer {
case '9':
continue OUTER;
default:
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
}
case 'A':
@@ -638,7 +646,7 @@ public class StreamLexer implements Lexer {
if ('0' <= ch && ch <= '9') {
eat();
} else {
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
OUTER:
while (true) {
@@ -650,7 +658,7 @@ public class StreamLexer implements Lexer {
if ('0' <= ch && ch <= '9') {
continue OUTER;
} else {
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
case '0':
case '1':
@@ -689,7 +697,7 @@ public class StreamLexer implements Lexer {
eat();
break;
default:
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
OUTER:
while (true) {
@@ -703,7 +711,7 @@ public class StreamLexer implements Lexer {
case '1':
continue OUTER;
default:
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
case '0':
case '1':
@@ -740,7 +748,7 @@ public class StreamLexer implements Lexer {
eat();
break;
default:
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
OUTER:
while (true) {
@@ -760,7 +768,7 @@ public class StreamLexer implements Lexer {
case '7':
continue OUTER;
default:
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
case '0':
case '1':
@@ -934,7 +942,7 @@ public class StreamLexer implements Lexer {
}
case '/':
// handled with comments
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
case '%':
eat();
@@ -953,7 +961,7 @@ public class StreamLexer implements Lexer {
return Token.XOR;
}
default:
- throw new ParseError(reader.position(), String.format("unexpected input: %c", ch));
+ throw error("unexpected input: %c", ch);
}
}
@@ -1146,4 +1154,8 @@ public class StreamLexer implements Lexer {
return Token.IDENT;
}
}
+
+ private TurbineError error(String message, Object... args) {
+ return TurbineError.format(reader.source(), reader.position(), message, args);
+ }
}
diff --git a/java/com/google/turbine/parse/UnicodeEscapePreprocessor.java b/java/com/google/turbine/parse/UnicodeEscapePreprocessor.java
index 92eef55..2bbd897 100644
--- a/java/com/google/turbine/parse/UnicodeEscapePreprocessor.java
+++ b/java/com/google/turbine/parse/UnicodeEscapePreprocessor.java
@@ -16,19 +16,24 @@
package com.google.turbine.parse;
+import com.google.turbine.diag.SourceFile;
+import com.google.turbine.diag.TurbineError;
+
/** Preprocesses Unicode escape characters in Java source code, as described in JLS ยง3.3. */
public class UnicodeEscapePreprocessor {
public static final char ASCII_SUB = 0x1A;
+ private final SourceFile source;
private final String input;
private int idx = 0;
private char ch;
private boolean evenLeadingSlashes = true;
- public UnicodeEscapePreprocessor(String input) {
- this.input = input;
+ public UnicodeEscapePreprocessor(SourceFile source) {
+ this.source = source;
+ this.input = source.source();
}
/** Returns the current position in the input. */
@@ -109,9 +114,9 @@ public class UnicodeEscapePreprocessor {
case 'f':
return ((d - 'a') + 10);
case ASCII_SUB:
- throw new ParseError(position(), "unexpected end of input");
+ throw new AssertionError("unexpected end of input");
default:
- throw new ParseError(position(), String.format("0x%x", (int) d));
+ throw TurbineError.format(source, position(), "0x%x", (int) d);
}
}
@@ -126,4 +131,8 @@ public class UnicodeEscapePreprocessor {
ch = done() ? ASCII_SUB : input.charAt(idx);
idx++;
}
+
+ public SourceFile source() {
+ return source;
+ }
}