1/*
2 * [The "BSD license"]
3 *  Copyright (c) 2010 Terence Parr
4 *  All rights reserved.
5 *
6 *  Redistribution and use in source and binary forms, with or without
7 *  modification, are permitted provided that the following conditions
8 *  are met:
9 *  1. Redistributions of source code must retain the above copyright
10 *      notice, this list of conditions and the following disclaimer.
11 *  2. Redistributions in binary form must reproduce the above copyright
12 *      notice, this list of conditions and the following disclaimer in the
13 *      documentation and/or other materials provided with the distribution.
14 *  3. The name of the author may not be used to endorse or promote products
15 *      derived from this software without specific prior written permission.
16 *
17 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29package org.antlr.tool;
30
31/** Track the names of attributes define in arg lists, return values,
32 *  scope blocks etc...
33 */
34public class Attribute {
35	/** The entire declaration such as "String foo;" */
36	public String decl;
37
38	/** The type; might be empty such as for Python which has no static typing */
39	public String type;
40
41	/** The name of the attribute "foo" */
42	public String name;
43
44	/** The optional attribute intialization expression */
45	public String initValue;
46
47	public Attribute(String decl) {
48		extractAttribute(decl);
49	}
50
51	public Attribute(String name, String decl) {
52		this.name = name;
53		this.decl = decl;
54	}
55
56	/** For decls like "String foo" or "char *foo32[3]" compute the ID
57	 *  and type declarations.  Also handle "int x=3" and 'T t = new T("foo")'
58	 *  but if the separator is ',' you cannot use ',' in the initvalue.
59	 *  AttributeScope.addAttributes takes care of the separation so we are
60	 *  free here to use from '=' to end of string as the expression.
61	 *
62	 *  Set name, type, initvalue, and full decl instance vars.
63	 */
64	protected void extractAttribute(String decl) {
65		if ( decl==null ) {
66			return;
67		}
68		boolean inID = false;
69		int start = -1;
70		int rightEdgeOfDeclarator = decl.length()-1;
71		int equalsIndex = decl.indexOf('=');
72		if ( equalsIndex>0 ) {
73			// everything after the '=' is the init value
74			this.initValue = decl.substring(equalsIndex+1,decl.length());
75			rightEdgeOfDeclarator = equalsIndex-1;
76		}
77		// walk backwards looking for start of an ID
78		for (int i=rightEdgeOfDeclarator; i>=0; i--) {
79			// if we haven't found the end yet, keep going
80			if ( !inID && Character.isLetterOrDigit(decl.charAt(i)) ) {
81			    inID = true;
82			}
83			else if ( inID &&
84				      !(Character.isLetterOrDigit(decl.charAt(i))||
85				       decl.charAt(i)=='_') ) {
86				start = i+1;
87				break;
88			}
89		}
90		if ( start<0 && inID ) {
91			start = 0;
92		}
93		if ( start<0 ) {
94			ErrorManager.error(ErrorManager.MSG_CANNOT_FIND_ATTRIBUTE_NAME_IN_DECL,decl);
95		}
96		// walk forwards looking for end of an ID
97		int stop=-1;
98		for (int i=start; i<=rightEdgeOfDeclarator; i++) {
99			// if we haven't found the end yet, keep going
100			if ( !(Character.isLetterOrDigit(decl.charAt(i))||
101				decl.charAt(i)=='_') )
102			{
103				stop = i;
104				break;
105			}
106			if ( i==rightEdgeOfDeclarator ) {
107				stop = i+1;
108			}
109		}
110
111		// the name is the last ID
112		this.name = decl.substring(start,stop);
113
114		// the type is the decl minus the ID (could be empty)
115		this.type = decl.substring(0,start);
116		if ( stop<=rightEdgeOfDeclarator ) {
117			this.type += decl.substring(stop,rightEdgeOfDeclarator+1);
118		}
119		this.type = type.trim();
120		if ( this.type.length()==0 ) {
121			this.type = null;
122		}
123
124		this.decl = decl;
125	}
126
127	public String toString() {
128		if ( initValue!=null ) {
129			return type+" "+name+"="+initValue;
130		}
131		return type+" "+name;
132	}
133}
134
135