UNPKG

10.3 kBTypeScriptView Raw
1/*!
2 * Copyright 2016 The ANTLR Project. All rights reserved.
3 * Licensed under the BSD-3-Clause license. See LICENSE file in the project root for license information.
4 */
5import { Interval } from "./misc/Interval";
6import { Token } from "./Token";
7import { TokenStream } from "./TokenStream";
8/**
9 * Useful for rewriting out a buffered input token stream after doing some
10 * augmentation or other manipulations on it.
11 *
12 * You can insert stuff, replace, and delete chunks. Note that the operations
13 * are done lazily--only if you convert the buffer to a {@link String} with
14 * {@link TokenStream#getText()}. This is very efficient because you are not
15 * moving data around all the time. As the buffer of tokens is converted to
16 * strings, the {@link #getText()} method(s) scan the input token stream and
17 * check to see if there is an operation at the current index. If so, the
18 * operation is done and then normal {@link String} rendering continues on the
19 * buffer. This is like having multiple Turing machine instruction streams
20 * (programs) operating on a single input tape. :)
21 *
22 * This rewriter makes no modifications to the token stream. It does not ask the
23 * stream to fill itself up nor does it advance the input cursor. The token
24 * stream `TokenStream.index` will return the same value before and
25 * after any {@link #getText()} call.
26 *
27 * The rewriter only works on tokens that you have in the buffer and ignores the
28 * current input cursor. If you are buffering tokens on-demand, calling
29 * {@link #getText()} halfway through the input will only do rewrites for those
30 * tokens in the first half of the file.
31 *
32 * Since the operations are done lazily at {@link #getText}-time, operations do
33 * not screw up the token index values. That is, an insert operation at token
34 * index `i` does not change the index values for tokens
35 * `i`+1..n-1.
36 *
37 * Because operations never actually alter the buffer, you may always get the
38 * original token stream back without undoing anything. Since the instructions
39 * are queued up, you can easily simulate transactions and roll back any changes
40 * if there is an error just by removing instructions. For example,
41 *
42 * ```
43 * CharStream input = new ANTLRFileStream("input");
44 * TLexer lex = new TLexer(input);
45 * CommonTokenStream tokens = new CommonTokenStream(lex);
46 * T parser = new T(tokens);
47 * TokenStreamRewriter rewriter = new TokenStreamRewriter(tokens);
48 * parser.startRule();
49 * ```
50 *
51 * Then in the rules, you can execute (assuming rewriter is visible):
52 *
53 * ```
54 * Token t,u;
55 * ...
56 * rewriter.insertAfter(t, "text to put after t");}
57 * rewriter.insertAfter(u, "text after u");}
58 * System.out.println(rewriter.getText());
59 * ```
60 *
61 * You can also have multiple "instruction streams" and get multiple rewrites
62 * from a single pass over the input. Just name the instruction streams and use
63 * that name again when printing the buffer. This could be useful for generating
64 * a C file and also its header file--all from the same buffer:
65 *
66 * ```
67 * rewriter.insertAfter("pass1", t, "text to put after t");}
68 * rewriter.insertAfter("pass2", u, "text after u");}
69 * System.out.println(rewriter.getText("pass1"));
70 * System.out.println(rewriter.getText("pass2"));
71 * ```
72 *
73 * If you don't use named rewrite streams, a "default" stream is used as the
74 * first example shows.
75 */
76export declare class TokenStreamRewriter {
77 static readonly DEFAULT_PROGRAM_NAME: string;
78 static readonly PROGRAM_INIT_SIZE: number;
79 static readonly MIN_TOKEN_INDEX: number;
80 /** Our source stream */
81 protected tokens: TokenStream;
82 /** You may have multiple, named streams of rewrite operations.
83 * I'm calling these things "programs."
84 * Maps String (name) → rewrite (List)
85 */
86 protected programs: Map<string, RewriteOperation[]>;
87 /** Map String (program name) &rarr; Integer index */
88 protected lastRewriteTokenIndexes: Map<string, number>;
89 constructor(tokens: TokenStream);
90 getTokenStream(): TokenStream;
91 rollback(instructionIndex: number): void;
92 /** Rollback the instruction stream for a program so that
93 * the indicated instruction (via instructionIndex) is no
94 * longer in the stream. UNTESTED!
95 */
96 rollback(instructionIndex: number, programName: string): void;
97 deleteProgram(): void;
98 /** Reset the program so that no instructions exist */
99 deleteProgram(programName: string): void;
100 insertAfter(t: Token, text: {}): void;
101 insertAfter(index: number, text: {}): void;
102 insertAfter(t: Token, text: {}, programName: string): void;
103 insertAfter(index: number, text: {}, programName: string): void;
104 insertBefore(t: Token, text: {}): void;
105 insertBefore(index: number, text: {}): void;
106 insertBefore(t: Token, text: {}, programName: string): void;
107 insertBefore(index: number, text: {}, programName: string): void;
108 replaceSingle(index: number, text: {}): void;
109 replaceSingle(indexT: Token, text: {}): void;
110 replace(from: number, to: number, text: {}): void;
111 replace(from: Token, to: Token, text: {}): void;
112 replace(from: number, to: number, text: {}, programName: string): void;
113 replace(from: Token, to: Token, text: {}, programName: string): void;
114 delete(index: number): void;
115 delete(from: number, to: number): void;
116 delete(indexT: Token): void;
117 delete(from: Token, to: Token): void;
118 delete(from: number, to: number, programName: string): void;
119 delete(from: Token, to: Token, programName: string): void;
120 protected getLastRewriteTokenIndex(): number;
121 protected getLastRewriteTokenIndex(programName: string): number;
122 protected setLastRewriteTokenIndex(programName: string, i: number): void;
123 protected getProgram(name: string): RewriteOperation[];
124 private initializeProgram;
125 /** Return the text from the original tokens altered per the
126 * instructions given to this rewriter.
127 */
128 getText(): string;
129 /** Return the text from the original tokens altered per the
130 * instructions given to this rewriter in programName.
131 *
132 * @since 4.5
133 */
134 getText(programName: string): string;
135 /** Return the text associated with the tokens in the interval from the
136 * original token stream but with the alterations given to this rewriter.
137 * The interval refers to the indexes in the original token stream.
138 * We do not alter the token stream in any way, so the indexes
139 * and intervals are still consistent. Includes any operations done
140 * to the first and last token in the interval. So, if you did an
141 * insertBefore on the first token, you would get that insertion.
142 * The same is true if you do an insertAfter the stop token.
143 */
144 getText(interval: Interval): string;
145 getText(interval: Interval, programName: string): string;
146 /** We need to combine operations and report invalid operations (like
147 * overlapping replaces that are not completed nested). Inserts to
148 * same index need to be combined etc... Here are the cases:
149 *
150 * I.i.u I.j.v leave alone, nonoverlapping
151 * I.i.u I.i.v combine: Iivu
152 *
153 * R.i-j.u R.x-y.v | i-j in x-y delete first R
154 * R.i-j.u R.i-j.v delete first R
155 * R.i-j.u R.x-y.v | x-y in i-j ERROR
156 * R.i-j.u R.x-y.v | boundaries overlap ERROR
157 *
158 * Delete special case of replace (text==undefined):
159 * D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right)
160 *
161 * I.i.u R.x-y.v | i in (x+1)-y delete I (since insert before
162 * we're not deleting i)
163 * I.i.u R.x-y.v | i not in (x+1)-y leave alone, nonoverlapping
164 * R.x-y.v I.i.u | i in x-y ERROR
165 * R.x-y.v I.x.u R.x-y.uv (combine, delete I)
166 * R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping
167 *
168 * I.i.u = insert u before op @ index i
169 * R.x-y.u = replace x-y indexed tokens with u
170 *
171 * First we need to examine replaces. For any replace op:
172 *
173 * 1. wipe out any insertions before op within that range.
174 * 2. Drop any replace op before that is contained completely within
175 * that range.
176 * 3. Throw exception upon boundary overlap with any previous replace.
177 *
178 * Then we can deal with inserts:
179 *
180 * 1. for any inserts to same index, combine even if not adjacent.
181 * 2. for any prior replace with same left boundary, combine this
182 * insert with replace and delete this replace.
183 * 3. throw exception if index in same range as previous replace
184 *
185 * Don't actually delete; make op undefined in list. Easier to walk list.
186 * Later we can throw as we add to index &rarr; op map.
187 *
188 * Note that I.2 R.2-2 will wipe out I.2 even though, technically, the
189 * inserted stuff would be before the replace range. But, if you
190 * add tokens in front of a method body '{' and then delete the method
191 * body, I think the stuff before the '{' you added should disappear too.
192 *
193 * Return a map from token index to operation.
194 */
195 protected reduceToSingleOperationPerIndex(rewrites: Array<RewriteOperation | undefined>): Map<number, RewriteOperation>;
196 protected catOpText(a: {}, b: {}): string;
197 /** Get all operations before an index of a particular kind */
198 protected getKindOfOps<T extends RewriteOperation>(rewrites: Array<RewriteOperation | undefined>, kind: {
199 new (...args: any[]): T;
200 }, before: number): T[];
201}
202export declare class RewriteOperation {
203 protected readonly tokens: TokenStream;
204 /** What index into rewrites List are we? */
205 readonly instructionIndex: number;
206 /** Token buffer index. */
207 index: number;
208 text: {};
209 constructor(tokens: TokenStream, index: number, instructionIndex: number);
210 constructor(tokens: TokenStream, index: number, instructionIndex: number, text: {});
211 /** Execute the rewrite operation by possibly adding to the buffer.
212 * Return the index of the next token to operate on.
213 */
214 execute(buf: string[]): number;
215 toString(): string;
216}