xref: /aosp_15_r20/external/antlr/runtime/ObjC/Framework/BufferedTokenStream.m (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
1*16467b97STreehugger Robot// [The "BSD licence"]
2*16467b97STreehugger Robot// Copyright (c) 2010 Alan Condit
3*16467b97STreehugger Robot// All rights reserved.
4*16467b97STreehugger Robot//
5*16467b97STreehugger Robot// Redistribution and use in source and binary forms, with or without
6*16467b97STreehugger Robot// modification, are permitted provided that the following conditions
7*16467b97STreehugger Robot// are met:
8*16467b97STreehugger Robot// 1. Redistributions of source code must retain the above copyright
9*16467b97STreehugger Robot//    notice, this list of conditions and the following disclaimer.
10*16467b97STreehugger Robot// 2. Redistributions in binary form must reproduce the above copyright
11*16467b97STreehugger Robot//    notice, this list of conditions and the following disclaimer in the
12*16467b97STreehugger Robot//    documentation and/or other materials provided with the distribution.
13*16467b97STreehugger Robot// 3. The name of the author may not be used to endorse or promote products
14*16467b97STreehugger Robot//    derived from this software without specific prior written permission.
15*16467b97STreehugger Robot//
16*16467b97STreehugger Robot// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*16467b97STreehugger Robot// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*16467b97STreehugger Robot// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*16467b97STreehugger Robot// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*16467b97STreehugger Robot// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*16467b97STreehugger Robot// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*16467b97STreehugger Robot// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*16467b97STreehugger Robot// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*16467b97STreehugger Robot// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*16467b97STreehugger Robot// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*16467b97STreehugger Robot
27*16467b97STreehugger Robot#import "BufferedTokenStream.h"
28*16467b97STreehugger Robot#import "TokenSource.h"
29*16467b97STreehugger Robot#import "CommonTreeAdaptor.h"
30*16467b97STreehugger Robot#import "RuntimeException.h"
31*16467b97STreehugger Robot
32*16467b97STreehugger Robotextern NSInteger debug;
33*16467b97STreehugger Robot
34*16467b97STreehugger Robot@implementation BufferedTokenStream
35*16467b97STreehugger Robot
36*16467b97STreehugger Robot@synthesize tokenSource;
37*16467b97STreehugger Robot@synthesize tokens;
38*16467b97STreehugger Robot@synthesize lastMarker;
39*16467b97STreehugger Robot@synthesize index;
40*16467b97STreehugger Robot@synthesize range;
41*16467b97STreehugger Robot
42*16467b97STreehugger Robot+ (BufferedTokenStream *) newBufferedTokenStream
43*16467b97STreehugger Robot{
44*16467b97STreehugger Robot    return [[BufferedTokenStream alloc] init];
45*16467b97STreehugger Robot}
46*16467b97STreehugger Robot
47*16467b97STreehugger Robot+ (BufferedTokenStream *) newBufferedTokenStreamWith:(id<TokenSource>)aSource
48*16467b97STreehugger Robot{
49*16467b97STreehugger Robot    return [[BufferedTokenStream alloc] initWithTokenSource:aSource];
50*16467b97STreehugger Robot}
51*16467b97STreehugger Robot
52*16467b97STreehugger Robot- (BufferedTokenStream *) init
53*16467b97STreehugger Robot{
54*16467b97STreehugger Robot	if ((self = [super init]) != nil)
55*16467b97STreehugger Robot	{
56*16467b97STreehugger Robot        tokenSource = nil;
57*16467b97STreehugger Robot        tokens = [[AMutableArray arrayWithCapacity:1000] retain];
58*16467b97STreehugger Robot        index = -1;
59*16467b97STreehugger Robot        range = -1;
60*16467b97STreehugger Robot	}
61*16467b97STreehugger Robot	return self;
62*16467b97STreehugger Robot}
63*16467b97STreehugger Robot
64*16467b97STreehugger Robot-(id) initWithTokenSource:(id<TokenSource>)aSource
65*16467b97STreehugger Robot{
66*16467b97STreehugger Robot	if ((self = [super init]) != nil)
67*16467b97STreehugger Robot	{
68*16467b97STreehugger Robot        tokenSource = [aSource retain];
69*16467b97STreehugger Robot        tokens = [[AMutableArray arrayWithCapacity:1000] retain];
70*16467b97STreehugger Robot        index = -1;
71*16467b97STreehugger Robot        range = -1;
72*16467b97STreehugger Robot	}
73*16467b97STreehugger Robot	return self;
74*16467b97STreehugger Robot}
75*16467b97STreehugger Robot
76*16467b97STreehugger Robot- (id) copyWithZone:(NSZone *)aZone
77*16467b97STreehugger Robot{
78*16467b97STreehugger Robot    BufferedTokenStream *copy;
79*16467b97STreehugger Robot
80*16467b97STreehugger Robot    copy = [[[self class] allocWithZone:aZone] init];
81*16467b97STreehugger Robot    copy.tokenSource = self.tokenSource;
82*16467b97STreehugger Robot    if ( self.tokens )
83*16467b97STreehugger Robot        copy.tokens = [tokens copyWithZone:aZone];
84*16467b97STreehugger Robot    copy.lastMarker = self.lastMarker;
85*16467b97STreehugger Robot    copy.index = self.index;
86*16467b97STreehugger Robot    copy.range = self.range;
87*16467b97STreehugger Robot    return copy;
88*16467b97STreehugger Robot}
89*16467b97STreehugger Robot
90*16467b97STreehugger Robot- (void)dealloc
91*16467b97STreehugger Robot{
92*16467b97STreehugger Robot#ifdef DEBUG_DEALLOC
93*16467b97STreehugger Robot    NSLog( @"called dealloc in BufferedTokenStream" );
94*16467b97STreehugger Robot#endif
95*16467b97STreehugger Robot    if ( tokens ) [tokens release];
96*16467b97STreehugger Robot    if ( tokenSource ) [tokenSource release];
97*16467b97STreehugger Robot	[super dealloc];
98*16467b97STreehugger Robot}
99*16467b97STreehugger Robot
100*16467b97STreehugger Robot- (NSUInteger)line
101*16467b97STreehugger Robot{
102*16467b97STreehugger Robot    return ((CommonToken *)[tokens objectAtIndex:index]).line;
103*16467b97STreehugger Robot}
104*16467b97STreehugger Robot
105*16467b97STreehugger Robot- (NSUInteger)charPositionInLine
106*16467b97STreehugger Robot{
107*16467b97STreehugger Robot    return ((CommonToken *)[tokens objectAtIndex:index]).charPositionInLine;
108*16467b97STreehugger Robot}
109*16467b97STreehugger Robot
110*16467b97STreehugger Robot- (id<TokenSource>) getTokenSource
111*16467b97STreehugger Robot{
112*16467b97STreehugger Robot    return tokenSource;
113*16467b97STreehugger Robot}
114*16467b97STreehugger Robot
115*16467b97STreehugger Robot- (NSInteger) getRange
116*16467b97STreehugger Robot{
117*16467b97STreehugger Robot    return range;
118*16467b97STreehugger Robot}
119*16467b97STreehugger Robot
120*16467b97STreehugger Robot- (void) setRange:(NSInteger)anInt
121*16467b97STreehugger Robot{
122*16467b97STreehugger Robot    range = anInt;
123*16467b97STreehugger Robot}
124*16467b97STreehugger Robot
125*16467b97STreehugger Robot- (NSInteger) mark
126*16467b97STreehugger Robot{
127*16467b97STreehugger Robot    if ( index == -1 ) {
128*16467b97STreehugger Robot        [self setup];
129*16467b97STreehugger Robot//        [self fill];
130*16467b97STreehugger Robot    }
131*16467b97STreehugger Robot    lastMarker = self.index;
132*16467b97STreehugger Robot    return lastMarker;
133*16467b97STreehugger Robot}
134*16467b97STreehugger Robot
135*16467b97STreehugger Robot- (void) release:(NSInteger) marker
136*16467b97STreehugger Robot{
137*16467b97STreehugger Robot    // no resources to release
138*16467b97STreehugger Robot}
139*16467b97STreehugger Robot
140*16467b97STreehugger Robot- (void) rewind:(NSInteger) marker
141*16467b97STreehugger Robot{
142*16467b97STreehugger Robot    [self seek:marker];
143*16467b97STreehugger Robot}
144*16467b97STreehugger Robot
145*16467b97STreehugger Robot- (void) rewind
146*16467b97STreehugger Robot{
147*16467b97STreehugger Robot    [self seek:lastMarker];
148*16467b97STreehugger Robot}
149*16467b97STreehugger Robot
150*16467b97STreehugger Robot- (void) reset
151*16467b97STreehugger Robot{
152*16467b97STreehugger Robot    index = 0;
153*16467b97STreehugger Robot    lastMarker = 0;
154*16467b97STreehugger Robot}
155*16467b97STreehugger Robot
156*16467b97STreehugger Robot- (void) seek:(NSInteger) anIndex
157*16467b97STreehugger Robot{
158*16467b97STreehugger Robot    index = anIndex;
159*16467b97STreehugger Robot}
160*16467b97STreehugger Robot
161*16467b97STreehugger Robot- (NSInteger) size
162*16467b97STreehugger Robot{
163*16467b97STreehugger Robot    return [tokens count];
164*16467b97STreehugger Robot}
165*16467b97STreehugger Robot
166*16467b97STreehugger Robot/** Move the input pointer to the next incoming token.  The stream
167*16467b97STreehugger Robot *  must become active with LT(1) available.  consume() simply
168*16467b97STreehugger Robot *  moves the input pointer so that LT(1) points at the next
169*16467b97STreehugger Robot *  input symbol. Consume at least one token.
170*16467b97STreehugger Robot *
171*16467b97STreehugger Robot *  Walk past any token not on the channel the parser is listening to.
172*16467b97STreehugger Robot */
173*16467b97STreehugger Robot- (void) consume
174*16467b97STreehugger Robot{
175*16467b97STreehugger Robot    if ( index == -1 ) {
176*16467b97STreehugger Robot        [self setup];
177*16467b97STreehugger Robot//        [self fill];
178*16467b97STreehugger Robot    }
179*16467b97STreehugger Robot    index++;
180*16467b97STreehugger Robot    [self sync:index];
181*16467b97STreehugger Robot}
182*16467b97STreehugger Robot
183*16467b97STreehugger Robot/** Make sure index i in tokens has a token. */
184*16467b97STreehugger Robot- (void) sync:(NSInteger) i
185*16467b97STreehugger Robot{
186*16467b97STreehugger Robot    // how many more elements we need?
187*16467b97STreehugger Robot    NSInteger n = (i - [tokens count]) + 1;
188*16467b97STreehugger Robot    if (debug > 1) NSLog(@"[self sync:%d] needs %d\n", i, n);
189*16467b97STreehugger Robot    if ( n > 0 )
190*16467b97STreehugger Robot        [self fetch:n];
191*16467b97STreehugger Robot}
192*16467b97STreehugger Robot
193*16467b97STreehugger Robot/** add n elements to buffer */
194*16467b97STreehugger Robot- (void) fetch:(NSInteger)n
195*16467b97STreehugger Robot{
196*16467b97STreehugger Robot    for (NSInteger i=1; i <= n; i++) {
197*16467b97STreehugger Robot        id<Token> t = [tokenSource nextToken];
198*16467b97STreehugger Robot        [t setTokenIndex:[tokens count]];
199*16467b97STreehugger Robot        if (debug > 1) NSLog(@"adding %@ at index %d\n", [t text], [tokens count]);
200*16467b97STreehugger Robot        [tokens addObject:t];
201*16467b97STreehugger Robot        if ( t.type == TokenTypeEOF )
202*16467b97STreehugger Robot            break;
203*16467b97STreehugger Robot    }
204*16467b97STreehugger Robot}
205*16467b97STreehugger Robot
206*16467b97STreehugger Robot- (id<Token>) getToken:(NSInteger) i
207*16467b97STreehugger Robot{
208*16467b97STreehugger Robot    if ( i < 0 || i >= [tokens count] ) {
209*16467b97STreehugger Robot        @throw [NoSuchElementException newException:[NSString stringWithFormat:@"token index %d out of range 0..%d", i, [tokens count]-1]];
210*16467b97STreehugger Robot    }
211*16467b97STreehugger Robot    return [tokens objectAtIndex:i];
212*16467b97STreehugger Robot}
213*16467b97STreehugger Robot
214*16467b97STreehugger Robot/** Get all tokens from start..stop inclusively */
215*16467b97STreehugger Robot- (AMutableArray *)getFrom:(NSInteger)startIndex To:(NSInteger)stopIndex
216*16467b97STreehugger Robot{
217*16467b97STreehugger Robot    if ( startIndex < 0 || stopIndex < 0 )
218*16467b97STreehugger Robot        return nil;
219*16467b97STreehugger Robot    if ( index == -1 ) {
220*16467b97STreehugger Robot        [self setup];
221*16467b97STreehugger Robot//        [self fill];
222*16467b97STreehugger Robot    }
223*16467b97STreehugger Robot    AMutableArray *subset = [AMutableArray arrayWithCapacity:5];
224*16467b97STreehugger Robot    if ( stopIndex >= [tokens count] )
225*16467b97STreehugger Robot        stopIndex = [tokens count]-1;
226*16467b97STreehugger Robot    for (NSInteger i = startIndex; i <= stopIndex; i++) {
227*16467b97STreehugger Robot        id<Token>t = [tokens objectAtIndex:i];
228*16467b97STreehugger Robot        if ( t.type == TokenTypeEOF )
229*16467b97STreehugger Robot            break;
230*16467b97STreehugger Robot        [subset addObject:t];
231*16467b97STreehugger Robot    }
232*16467b97STreehugger Robot    return subset;
233*16467b97STreehugger Robot}
234*16467b97STreehugger Robot
235*16467b97STreehugger Robot- (NSInteger) LA:(NSInteger)i
236*16467b97STreehugger Robot{
237*16467b97STreehugger Robot    return [[self LT:i] type];
238*16467b97STreehugger Robot}
239*16467b97STreehugger Robot
240*16467b97STreehugger Robot- (id<Token>) LB:(NSInteger)k
241*16467b97STreehugger Robot{
242*16467b97STreehugger Robot    if ( (index - k) < 0 )
243*16467b97STreehugger Robot        return nil;
244*16467b97STreehugger Robot    return [tokens objectAtIndex:(index-k)];
245*16467b97STreehugger Robot}
246*16467b97STreehugger Robot
247*16467b97STreehugger Robot- (id<Token>) LT:(NSInteger)k
248*16467b97STreehugger Robot{
249*16467b97STreehugger Robot    if ( index == -1 ) {
250*16467b97STreehugger Robot        [self setup];
251*16467b97STreehugger Robot//        [self fill];
252*16467b97STreehugger Robot    }
253*16467b97STreehugger Robot    if ( k == 0 )
254*16467b97STreehugger Robot        return nil;
255*16467b97STreehugger Robot    if ( k < 0 )
256*16467b97STreehugger Robot        return [self LB:-k];
257*16467b97STreehugger Robot
258*16467b97STreehugger Robot    NSInteger i = index + k - 1;
259*16467b97STreehugger Robot    [self sync:i];
260*16467b97STreehugger Robot    if ( i >= [tokens count] ) { // return EOF token
261*16467b97STreehugger Robot                                // EOF must be last token
262*16467b97STreehugger Robot        return [tokens objectAtIndex:([tokens count]-1)];
263*16467b97STreehugger Robot    }
264*16467b97STreehugger Robot    if ( i > range )
265*16467b97STreehugger Robot        range = i;
266*16467b97STreehugger Robot    return [tokens objectAtIndex:i];
267*16467b97STreehugger Robot}
268*16467b97STreehugger Robot
269*16467b97STreehugger Robot- (void) setup
270*16467b97STreehugger Robot{
271*16467b97STreehugger Robot    [self sync:0];
272*16467b97STreehugger Robot    index = 0;
273*16467b97STreehugger Robot}
274*16467b97STreehugger Robot
275*16467b97STreehugger Robot/** Reset this token stream by setting its token source. */
276*16467b97STreehugger Robot- (void) setTokenSource:(id<TokenSource>) aTokenSource
277*16467b97STreehugger Robot{
278*16467b97STreehugger Robot    tokenSource = aTokenSource;
279*16467b97STreehugger Robot    if ( [tokens count] )
280*16467b97STreehugger Robot        [tokens removeAllObjects];
281*16467b97STreehugger Robot    index = -1;
282*16467b97STreehugger Robot}
283*16467b97STreehugger Robot
284*16467b97STreehugger Robot- (AMutableArray *)getTokens
285*16467b97STreehugger Robot{
286*16467b97STreehugger Robot    return tokens;
287*16467b97STreehugger Robot}
288*16467b97STreehugger Robot
289*16467b97STreehugger Robot- (AMutableArray *)getTokensFrom:(NSInteger) startIndex To:(NSInteger) stopIndex
290*16467b97STreehugger Robot{
291*16467b97STreehugger Robot    return [self getTokensFrom:startIndex To:stopIndex With:(ANTLRBitSet *)nil];
292*16467b97STreehugger Robot}
293*16467b97STreehugger Robot
294*16467b97STreehugger Robot/** Given a start and stop index, return a List of all tokens in
295*16467b97STreehugger Robot *  the token type BitSet.  Return null if no tokens were found.  This
296*16467b97STreehugger Robot *  method looks at both on and off channel tokens.
297*16467b97STreehugger Robot */
298*16467b97STreehugger Robot- (AMutableArray *)getTokensFrom:(NSInteger)startIndex To:(NSInteger)stopIndex With:(ANTLRBitSet *)types
299*16467b97STreehugger Robot{
300*16467b97STreehugger Robot    if ( index == -1 ) {
301*16467b97STreehugger Robot        [self setup];
302*16467b97STreehugger Robot//        [self fill];
303*16467b97STreehugger Robot    }
304*16467b97STreehugger Robot    if ( stopIndex >= [tokens count] )
305*16467b97STreehugger Robot        stopIndex = [tokens count]-1;
306*16467b97STreehugger Robot    if ( startIndex < 0 )
307*16467b97STreehugger Robot        startIndex = 0;
308*16467b97STreehugger Robot    if ( startIndex > stopIndex )
309*16467b97STreehugger Robot        return nil;
310*16467b97STreehugger Robot
311*16467b97STreehugger Robot    // list = tokens[start:stop]:{Token t, t.getType() in types}
312*16467b97STreehugger Robot    AMutableArray *filteredTokens = [AMutableArray arrayWithCapacity:5];
313*16467b97STreehugger Robot    for (NSInteger i = startIndex; i <= stopIndex; i++) {
314*16467b97STreehugger Robot        id<Token>t = [tokens objectAtIndex:i];
315*16467b97STreehugger Robot        if ( types == nil || [types member:t.type] ) {
316*16467b97STreehugger Robot            [filteredTokens addObject:t];
317*16467b97STreehugger Robot        }
318*16467b97STreehugger Robot    }
319*16467b97STreehugger Robot    if ( [filteredTokens count] == 0 ) {
320*16467b97STreehugger Robot        filteredTokens = nil;
321*16467b97STreehugger Robot    }
322*16467b97STreehugger Robot    return filteredTokens;
323*16467b97STreehugger Robot}
324*16467b97STreehugger Robot
325*16467b97STreehugger Robot- (AMutableArray *)getTokensFrom:(NSInteger)startIndex To:(NSInteger)stopIndex WithType:(NSInteger)ttype
326*16467b97STreehugger Robot{
327*16467b97STreehugger Robot    return [self getTokensFrom:startIndex To:stopIndex With:[ANTLRBitSet of:ttype]];
328*16467b97STreehugger Robot}
329*16467b97STreehugger Robot
330*16467b97STreehugger Robot- (AMutableArray *)getTokensFrom:(NSInteger)startIndex To:(NSInteger)stopIndex WithList:(AMutableArray *)types
331*16467b97STreehugger Robot{
332*16467b97STreehugger Robot    return [self getTokensFrom:startIndex To:stopIndex With:[ANTLRBitSet newBitSetWithArray:types]];
333*16467b97STreehugger Robot}
334*16467b97STreehugger Robot
335*16467b97STreehugger Robot- (NSString *)getSourceName
336*16467b97STreehugger Robot{
337*16467b97STreehugger Robot    return [tokenSource getSourceName];
338*16467b97STreehugger Robot}
339*16467b97STreehugger Robot
340*16467b97STreehugger Robot/** Grab *all* tokens from stream and return string */
341*16467b97STreehugger Robot- (NSString *) toString
342*16467b97STreehugger Robot{
343*16467b97STreehugger Robot    if ( index == -1 ) {
344*16467b97STreehugger Robot        [self setup];
345*16467b97STreehugger Robot    }
346*16467b97STreehugger Robot    [self fill];
347*16467b97STreehugger Robot    return [self toStringFromStart:0 ToEnd:[tokens count]-1];
348*16467b97STreehugger Robot}
349*16467b97STreehugger Robot
350*16467b97STreehugger Robot- (NSString *) toStringFromStart:(NSInteger)startIdx ToEnd:(NSInteger)stopIdx
351*16467b97STreehugger Robot{
352*16467b97STreehugger Robot    if ( startIdx < 0 || stopIdx < 0 )
353*16467b97STreehugger Robot        return nil;
354*16467b97STreehugger Robot    if ( index == -1 ) {
355*16467b97STreehugger Robot        [self setup];
356*16467b97STreehugger Robot    }
357*16467b97STreehugger Robot    if ( stopIdx >= [tokens count] )
358*16467b97STreehugger Robot        stopIdx = [tokens count]-1;
359*16467b97STreehugger Robot    NSMutableString *buf = [NSMutableString stringWithCapacity:5];
360*16467b97STreehugger Robot    for (NSInteger i = startIdx; i <= stopIdx; i++) {
361*16467b97STreehugger Robot        id<Token>t = [tokens objectAtIndex:i];
362*16467b97STreehugger Robot        if ( t.type == TokenTypeEOF )
363*16467b97STreehugger Robot            break;
364*16467b97STreehugger Robot        [buf appendString:[t text]];
365*16467b97STreehugger Robot    }
366*16467b97STreehugger Robot    return buf;
367*16467b97STreehugger Robot}
368*16467b97STreehugger Robot
369*16467b97STreehugger Robot- (NSString *) toStringFromToken:(id<Token>)startToken ToToken:(id<Token>)stopToken
370*16467b97STreehugger Robot{
371*16467b97STreehugger Robot    if ( startToken != nil && stopToken != nil ) {
372*16467b97STreehugger Robot        return [self toStringFromStart:[startToken getTokenIndex] ToEnd:[stopToken getTokenIndex]];
373*16467b97STreehugger Robot    }
374*16467b97STreehugger Robot    return nil;
375*16467b97STreehugger Robot}
376*16467b97STreehugger Robot
377*16467b97STreehugger Robot/** Get all tokens from lexer until EOF */
378*16467b97STreehugger Robot- (void) fill
379*16467b97STreehugger Robot{
380*16467b97STreehugger Robot    if ( index == -1 ) [self setup];
381*16467b97STreehugger Robot    if ( [((CommonToken *)[tokens objectAtIndex:index]) type] == TokenTypeEOF )
382*16467b97STreehugger Robot        return;
383*16467b97STreehugger Robot
384*16467b97STreehugger Robot    NSInteger i = index+1;
385*16467b97STreehugger Robot    [self sync:i];
386*16467b97STreehugger Robot    while ( [((CommonToken *)[tokens objectAtIndex:i]) type] != TokenTypeEOF ) {
387*16467b97STreehugger Robot        i++;
388*16467b97STreehugger Robot        [self sync:i];
389*16467b97STreehugger Robot    }
390*16467b97STreehugger Robot}
391*16467b97STreehugger Robot
392*16467b97STreehugger Robot@end
393