1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.incubator.code.extern.impl;
27
28 import jdk.incubator.code.extern.impl.Position.LineMap;
29
30 import java.nio.CharBuffer;
31 import java.util.ArrayList;
32 import java.util.List;
33
34 import static jdk.incubator.code.extern.impl.Tokens.DUMMY;
35 import static jdk.incubator.code.extern.impl.Tokens.Token;
36
37 /**
38 * The lexical analyzer maps an input stream consisting of
39 * ASCII characters and Unicode escapes into a token sequence.
40 *
41 * <p><b>This is NOT part of any supported API.
42 * If you write code that depends on this, you do so at your own risk.
43 * This code and its internal interfaces are subject to change or
44 * deletion without notice.</b>
45 */
46 public final class Scanner implements Lexer {
47
48 private final Tokens tokens;
49
50 /**
51 * The token, set by nextToken().
52 */
53 private Token token;
54
55 /**
56 * The previous token, set by nextToken().
57 */
58 private Token prevToken;
59
60 /**
61 * Buffer of saved tokens (used during lookahead)
62 */
63 private final List<Token> savedTokens = new ArrayList<>();
64
65 private final JavaBasedTokenizer tokenizer;
66
67 Scanner(Factory fac, char[] buf, int inputLength) {
68 this(fac, new JavaBasedTokenizer(fac, buf, inputLength));
69 }
70
71 Scanner(Factory fac, JavaBasedTokenizer tokenizer) {
72 this.tokenizer = tokenizer;
73 tokens = fac.tokens;
74 token = prevToken = DUMMY;
75 }
76
77 public Token token() {
78 return token(0);
79 }
80
81 public Token token(int lookahead) {
82 if (lookahead == 0) {
83 return token;
84 } else {
85 ensureLookahead(lookahead);
86 return savedTokens.get(lookahead - 1);
87 }
88 }
89
90 //where
91 private void ensureLookahead(int lookahead) {
92 for (int i = savedTokens.size(); i < lookahead; i++) {
93 savedTokens.add(tokenizer.readToken());
94 }
95 }
96
97 public Token prevToken() {
98 return prevToken;
99 }
100
101 public void nextToken() {
102 prevToken = token;
103 if (!savedTokens.isEmpty()) {
104 token = savedTokens.remove(0);
105 } else {
106 token = tokenizer.readToken();
107 }
108 }
109
110 public LineMap getLineMap() {
111 return tokenizer.getLineMap();
112 }
113
114 public int errPos() {
115 return tokenizer.errPos();
116 }
117
118 public void errPos(int pos) {
119 tokenizer.errPos(pos);
120 }
121
122 public static final class Factory {
123 final Log log;
124 final Tokens tokens;
125
126 /**
127 * Create a new scanner factory.
128 */
129 Factory() {
130 this.log = new Log();
131 this.tokens = new Tokens();
132 }
133
134 public Scanner newScanner(CharSequence input) {
135 if (input instanceof CharBuffer charBuffer) {
136 return newScanner(toArray(charBuffer), charBuffer.limit());
137 } else {
138 char[] array = input.toString().toCharArray();
139 return newScanner(array, array.length);
140 }
141 }
142
143 public Scanner newScanner(char[] input, int inputLength) {
144 return new Scanner(this, input, inputLength);
145 }
146
147 static char[] toArray(CharBuffer buffer) {
148 if (buffer.hasArray())
149 return buffer.compact().flip().array();
150 else
151 return buffer.toString().toCharArray();
152 }
153
154 static final Factory INSTANCE = new Factory();
155 }
156
157 public static Factory factory() {
158 return Factory.INSTANCE;
159 }
160 }