0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.cnd.modelimpl.csm.core;
0043:
0044: import java.util.*;
0045:
0046: import antlr.collections.AST;
0047:
0048: import org.netbeans.modules.cnd.api.model.*;
0049: import org.netbeans.modules.cnd.api.model.deep.*;
0050: import org.netbeans.modules.cnd.utils.cache.TextCache;
0051: import org.netbeans.modules.cnd.modelimpl.parser.generated.CPPTokenTypes;
0052:
0053: import org.netbeans.modules.cnd.modelimpl.csm.*;
0054: import org.netbeans.modules.cnd.modelimpl.csm.deep.*;
0055: import org.netbeans.modules.cnd.modelimpl.parser.CsmAST;
0056: import org.netbeans.modules.cnd.utils.cache.CharSequenceKey;
0057:
0058: /**
0059: * @author Vladimir Kvasihn
0060: */
0061: public class AstRenderer {
0062:
0063: private FileImpl file;
0064:
0065: public AstRenderer(FileImpl fileImpl) {
0066: this .file = fileImpl;
0067: }
0068:
0069: public void render(AST root) {
0070: render(root, (NamespaceImpl) file.getProject()
0071: .getGlobalNamespace(), file);
0072: }
0073:
0074: public void render(AST tree, NamespaceImpl currentNamespace,
0075: MutableDeclarationsContainer container) {
0076: if (tree == null)
0077: return; // paranoia
0078: for (AST token = tree.getFirstChild(); token != null; token = token
0079: .getNextSibling()) {
0080: int type = token.getType();
0081: switch (type) {
0082: case CPPTokenTypes.CSM_LINKAGE_SPECIFICATION:
0083: render(token, currentNamespace, container);
0084: break;
0085: case CPPTokenTypes.CSM_NAMESPACE_DECLARATION:
0086: NamespaceDefinitionImpl ns = new NamespaceDefinitionImpl(
0087: token, file, currentNamespace);
0088: container.addDeclaration(ns);
0089: render(token, (NamespaceImpl) ns.getNamespace(), ns);
0090: break;
0091: case CPPTokenTypes.CSM_CLASS_DECLARATION:
0092: case CPPTokenTypes.CSM_TEMPLATE_CLASS_DECLARATION: {
0093: ClassImpl cls = TemplateUtils
0094: .isPartialClassSpecialization(token) ? ClassImplSpecialization
0095: .create(token, currentNamespace, file)
0096: : ClassImpl.create(token, currentNamespace,
0097: file);
0098: container.addDeclaration(cls);
0099: addTypedefs(
0100: renderTypedef(token, cls, currentNamespace),
0101: currentNamespace, container);
0102: renderVariableInClassifier(token, cls,
0103: currentNamespace, container);
0104: break;
0105: }
0106: case CPPTokenTypes.CSM_ENUM_DECLARATION: {
0107: CsmEnum csmEnum = EnumImpl.create(token,
0108: currentNamespace, file);
0109: container.addDeclaration(csmEnum);
0110: renderVariableInClassifier(token, csmEnum,
0111: currentNamespace, container);
0112: break;
0113: }
0114: case CPPTokenTypes.CSM_FUNCTION_DECLARATION:
0115: if (isFuncLikeVariable(token)) {
0116: if (renderFuncLikeVariable(token, currentNamespace,
0117: container)) {
0118: break;
0119: }
0120: }
0121: //nobreak!
0122: case CPPTokenTypes.CSM_FUNCTION_RET_FUN_DECLARATION:
0123: case CPPTokenTypes.CSM_FUNCTION_TEMPLATE_DECLARATION:
0124: case CPPTokenTypes.CSM_USER_TYPE_CAST:
0125: FunctionImpl fi = new FunctionImpl(token, file,
0126: currentNamespace);
0127: container.addDeclaration(fi);
0128: if (!fi.isStatic()) {
0129: currentNamespace.addDeclaration(fi);
0130: }
0131: break;
0132: case CPPTokenTypes.CSM_CTOR_DEFINITION:
0133: case CPPTokenTypes.CSM_CTOR_TEMPLATE_DEFINITION:
0134: container.addDeclaration(new ConstructorDefinitionImpl(
0135: token, file, null));
0136: break;
0137: case CPPTokenTypes.CSM_DTOR_DEFINITION:
0138: case CPPTokenTypes.CSM_DTOR_TEMPLATE_DEFINITION:
0139: container.addDeclaration(new DestructorDefinitionImpl(
0140: token, file));
0141: break;
0142: case CPPTokenTypes.CSM_FUNCTION_RET_FUN_DEFINITION:
0143: case CPPTokenTypes.CSM_FUNCTION_DEFINITION:
0144: case CPPTokenTypes.CSM_FUNCTION_TEMPLATE_DEFINITION:
0145: case CPPTokenTypes.CSM_USER_TYPE_CAST_DEFINITION:
0146: if (isMemberDefinition(token)) {
0147: container
0148: .addDeclaration(new FunctionDefinitionImpl(
0149: token, file, null));
0150: } else {
0151: FunctionDDImpl fddi = new FunctionDDImpl(token,
0152: file, currentNamespace);
0153: //fddi.setScope(currentNamespace);
0154: container.addDeclaration(fddi);
0155: if (!fddi.isStatic()) {
0156: currentNamespace.addDeclaration(fddi);
0157: }
0158: }
0159: break;
0160: case CPPTokenTypes.CSM_TEMPLATE_EXPLICIT_SPECIALIZATION:
0161: if (isClassSpecialization(token)) {
0162: ClassImpl spec = ClassImplSpecialization.create(
0163: token, currentNamespace, file);
0164: container.addDeclaration(spec);
0165: addTypedefs(renderTypedef(token, spec,
0166: currentNamespace), currentNamespace,
0167: container);
0168: } else {
0169: if (isMemberDefinition(token)) {
0170: // this is a template method specialization declaration (without a definition)
0171: container.addDeclaration(new FunctionImplEx(
0172: token, file, null));
0173: } else {
0174: FunctionImpl funct = new FunctionImpl(token,
0175: file, currentNamespace);
0176: container.addDeclaration(funct);
0177: if (!funct.isStatic()) {
0178: currentNamespace.addDeclaration(funct);
0179: }
0180: }
0181: }
0182: break;
0183: case CPPTokenTypes.CSM_TEMPLATE_FUNCTION_DEFINITION_EXPLICIT_SPECIALIZATION:
0184: if (isMemberDefinition(token)) {
0185: container
0186: .addDeclaration(new FunctionDefinitionImpl(
0187: token, file, null));
0188: } else {
0189: FunctionDDImpl fddit = new FunctionDDImpl(token,
0190: file, currentNamespace);
0191: container.addDeclaration(fddit);
0192: if (!fddit.isStatic()) {
0193: currentNamespace.addDeclaration(fddit);
0194: }
0195: }
0196: break;
0197: case CPPTokenTypes.CSM_NAMESPACE_ALIAS:
0198: container.addDeclaration(new NamespaceAliasImpl(token,
0199: file));
0200: break;
0201: case CPPTokenTypes.CSM_USING_DIRECTIVE:
0202: container.addDeclaration(new UsingDirectiveImpl(token,
0203: file));
0204: break;
0205: case CPPTokenTypes.CSM_USING_DECLARATION:
0206: container.addDeclaration(new UsingDeclarationImpl(
0207: token, file));
0208: break;
0209: case CPPTokenTypes.CSM_TEMPL_FWD_CL_OR_STAT_MEM:
0210: if (renderForwardClassDeclaration(token,
0211: currentNamespace, container, file)) {
0212: break;
0213: } else {
0214: renderForwardMemberDeclaration(token,
0215: currentNamespace, container, file);
0216: }
0217: break;
0218: case CPPTokenTypes.CSM_GENERIC_DECLARATION:
0219: if (renderNSP(token, currentNamespace, container, file)) {
0220: break;
0221: }
0222: if (renderVariable(token, currentNamespace, container)) {
0223: break;
0224: }
0225: if (renderForwardClassDeclaration(token,
0226: currentNamespace, container, file)) {
0227: break;
0228: }
0229: if (renderLinkageSpec(token, file, currentNamespace,
0230: container)) {
0231: break;
0232: }
0233: CsmTypedef[] typedefs = renderTypedef(token, file,
0234: currentNamespace);
0235: if (typedefs != null && typedefs.length > 0) {
0236: addTypedefs(typedefs, currentNamespace, container);
0237: break;
0238: }
0239: default:
0240: renderNSP(token, currentNamespace, container, file);
0241: }
0242: }
0243: }
0244:
0245: protected void addTypedefs(CsmTypedef[] typedefs,
0246: NamespaceImpl currentNamespace,
0247: MutableDeclarationsContainer container) {
0248: if (typedefs != null) {
0249: for (int i = 0; i < typedefs.length; i++) {
0250: // It could be important to register in project before add as member...
0251: file.getProjectImpl().registerDeclaration(typedefs[i]);
0252: if (container != null) {
0253: container.addDeclaration(typedefs[i]);
0254: }
0255: if (currentNamespace != null) {
0256: // Note: DeclarationStatementImpl.DSRenderer can call with null namespace
0257: currentNamespace.addDeclaration(typedefs[i]);
0258: }
0259: }
0260: }
0261: }
0262:
0263: /**
0264: * Parser don't use a symbol table, so constructs like
0265: * int a(b)
0266: * are parsed as if they were functions.
0267: * At the moment of rendering, we check whether this is a variable of a function
0268: * @return true if it's a variable, otherwise false (it's a function)
0269: */
0270: private boolean isFuncLikeVariable(AST ast) {
0271: AST astParmList = AstUtil.findChildOfType(ast,
0272: CPPTokenTypes.CSM_PARMLIST);
0273: if (astParmList != null) {
0274: for (AST node = astParmList.getFirstChild(); node != null; node = node
0275: .getNextSibling()) {
0276: if (!isRefToVariable(node)) {
0277: return false;
0278: }
0279: }
0280: return true;
0281: }
0282: return false;
0283: }
0284:
0285: /**
0286: * Determines whether the given parameter can actually be a reference to a variable,
0287: * not a parameter
0288: * @param node an AST node that corresponds to parameter
0289: * @return true if might be just a reference to a variable, otherwise false
0290: */
0291: private boolean isRefToVariable(AST node) {
0292:
0293: if (node.getType() != CPPTokenTypes.CSM_PARAMETER_DECLARATION) { // paranoja
0294: return false;
0295: }
0296:
0297: AST child = node.getFirstChild();
0298:
0299: AST name = null;
0300:
0301: // AST structure is different for int f1(A) and int f2(*A)
0302: if (child != null
0303: && child.getType() == CPPTokenTypes.CSM_PTR_OPERATOR) {
0304: while (child != null
0305: && child.getType() == CPPTokenTypes.CSM_PTR_OPERATOR) {
0306: child = child.getNextSibling();
0307: }
0308: // now it's CSM_VARIABLE_DECLARATION
0309: if (child != null) {
0310: name = child.getFirstChild();
0311: }
0312: } else if (child.getType() == CPPTokenTypes.CSM_TYPE_COMPOUND) {
0313: if (child.getNextSibling() != null) {
0314: return false;
0315: }
0316: name = child.getFirstChild();
0317: }
0318:
0319: if (name == null) {
0320: return false;
0321: }
0322: if (name.getType() != CPPTokenTypes.CSM_QUALIFIED_ID
0323: && name.getType() != CPPTokenTypes.ID) {
0324: return false;
0325: }
0326:
0327: CsmAST csmAST = AstUtil.getFirstCsmAST(name);
0328: if (name == null) {
0329: return false;
0330: }
0331:
0332: return findVariable(name.getText(), csmAST.getOffset());
0333: }
0334:
0335: /**
0336: * Finds variable in globals and in the current file
0337: */
0338: private boolean findVariable(CharSequence name, int offset) {
0339: String uname = Utils
0340: .getCsmDeclarationKindkey(CsmDeclaration.Kind.VARIABLE)
0341: + OffsetableDeclarationBase.UNIQUE_NAME_SEPARATOR
0342: + "::" + name;
0343: if (findGlobal(file.getProject(), uname,
0344: new ArrayList<CsmProject>())) {
0345: return true;
0346: }
0347: return findVariable(name, file.getDeclarations(), offset);
0348: }
0349:
0350: private boolean findGlobal(CsmProject project, String uname,
0351: Collection<CsmProject> processedProjects) {
0352: if (processedProjects.contains(project)) {
0353: return false;
0354: }
0355: processedProjects.add(project);
0356: if (project.findDeclaration(uname) != null) {
0357: return true;
0358: }
0359: for (CsmProject lib : project.getLibraries()) {
0360: if (findGlobal(lib, uname, processedProjects)) {
0361: return true;
0362: }
0363: }
0364: return false;
0365: }
0366:
0367: private boolean findVariable(CharSequence name,
0368: Collection<CsmOffsetableDeclaration> declarations,
0369: int offset) {
0370: for (CsmOffsetableDeclaration decl : declarations) {
0371: if (decl.getStartOffset() >= offset) {
0372: break;
0373: }
0374: switch (decl.getKind()) {
0375: case VARIABLE:
0376: if (CharSequenceKey.Comparator.compare(name,
0377: ((CsmVariable) decl).getName()) == 0) {
0378: return true;
0379: }
0380: break;
0381: case NAMESPACE_DEFINITION:
0382: CsmNamespaceDefinition nd = (CsmNamespaceDefinition) decl;
0383: if (nd.getStartOffset() <= offset
0384: && nd.getEndOffset() >= offset) {
0385: if (findVariable(name, nd.getDeclarations(), offset)) {
0386: return true;
0387: }
0388: }
0389: break;
0390: }
0391: }
0392: return false;
0393: }
0394:
0395: /**
0396: * In the case of the "function-like variable" - construct like
0397: * int a(b)
0398: * renders the AST to create the variable
0399: */
0400: private boolean renderFuncLikeVariable(AST token,
0401: NamespaceImpl currentNamespace,
0402: MutableDeclarationsContainer container) {
0403: if (token != null) {
0404: token = token.getFirstChild();
0405: switch (token.getType()) {
0406: case CPPTokenTypes.CSM_TYPE_BUILTIN:
0407: case CPPTokenTypes.CSM_TYPE_COMPOUND:
0408: AST typeToken = token;
0409: AST next = token.getNextSibling();
0410: while (next != null
0411: && next.getType() == CPPTokenTypes.CSM_PTR_OPERATOR) {
0412: next = next.getNextSibling();
0413: }
0414: if (next != null
0415: && next.getType() == CPPTokenTypes.CSM_QUALIFIED_ID) {
0416: TypeImpl type;
0417: if (typeToken.getType() == CPPTokenTypes.CSM_TYPE_BUILTIN) {
0418: type = TypeFactory.createBuiltinType(typeToken
0419: .getText(), null, 0, typeToken, file);
0420: } else {
0421: type = TypeFactory.createType(typeToken, file,
0422: null, 0);
0423: }
0424: String name = next.getText();
0425: VariableImpl var = createVariable(next, file, type,
0426: name, false, currentNamespace, container,
0427: null);
0428: if (currentNamespace != null) {
0429: currentNamespace.addDeclaration(var);
0430: }
0431: if (container != null) {
0432: container.addDeclaration(var);
0433: }
0434: return true;
0435: }
0436: break;
0437:
0438: }
0439: }
0440: return false;
0441: }
0442:
0443: private boolean renderLinkageSpec(AST ast, FileImpl file,
0444: NamespaceImpl currentNamespace,
0445: MutableDeclarationsContainer container) {
0446: if (ast != null) {
0447: AST token = ast.getFirstChild();
0448: if (token.getType() == CPPTokenTypes.CSM_LINKAGE_SPECIFICATION) {
0449: render(token, currentNamespace, container);
0450: return true;
0451: }
0452: }
0453: return false;
0454: }
0455:
0456: protected void renderVariableInClassifier(AST ast,
0457: CsmClassifier classifier,
0458: MutableDeclarationsContainer container1,
0459: MutableDeclarationsContainer container2) {
0460: AST token = ast.getFirstChild();
0461: for (; token != null; token = token.getNextSibling()) {
0462: if (token.getType() == CPPTokenTypes.RCURLY) {
0463: break;
0464: }
0465: }
0466: if (token != null) {
0467: AST ptrOperator = null;
0468: for (; token != null; token = token.getNextSibling()) {
0469: switch (token.getType()) {
0470: case CPPTokenTypes.CSM_PTR_OPERATOR:
0471: if (ptrOperator == null) {
0472: ptrOperator = token;
0473: }
0474: break;
0475: case CPPTokenTypes.CSM_VARIABLE_DECLARATION:
0476: case CPPTokenTypes.CSM_ARRAY_DECLARATION: {
0477: int arrayDepth = 0;
0478: String name = null;
0479: for (AST varNode = token.getFirstChild(); varNode != null; varNode = varNode
0480: .getNextSibling()) {
0481: switch (varNode.getType()) {
0482: case CPPTokenTypes.LSQUARE:
0483: arrayDepth++;
0484: break;
0485: case CPPTokenTypes.CSM_QUALIFIED_ID:
0486: case CPPTokenTypes.ID:
0487: name = varNode.getText();
0488: break;
0489: }
0490: }
0491: if (name != null) {
0492: CsmType type = TypeFactory.createType(
0493: classifier, ptrOperator, arrayDepth,
0494: token, file);
0495: VariableImpl var = createVariable(token, file,
0496: type, name, false, container1,
0497: container2, null);
0498: if (container2 != null) {
0499: container2.addDeclaration(var);
0500: }
0501: // TODO! don't add to namespace if....
0502: if (container1 != null) {
0503: container1.addDeclaration(var);
0504: }
0505: ptrOperator = null;
0506: }
0507: }
0508: }
0509: }
0510: }
0511: }
0512:
0513: protected CsmTypedef[] renderTypedef(AST ast, CsmClass cls,
0514: CsmObject container) {
0515:
0516: List<CsmTypedef> results = new ArrayList<CsmTypedef>();
0517:
0518: AST typedefNode = ast.getFirstChild();
0519:
0520: if (typedefNode != null
0521: && typedefNode.getType() == CPPTokenTypes.LITERAL_typedef) {
0522:
0523: AST classNode = typedefNode.getNextSibling();
0524:
0525: switch (classNode.getType()) {
0526:
0527: case CPPTokenTypes.LITERAL_class:
0528: case CPPTokenTypes.LITERAL_union:
0529: case CPPTokenTypes.LITERAL_struct:
0530:
0531: AST curr = AstUtil.findSiblingOfType(classNode,
0532: CPPTokenTypes.RCURLY);
0533: if (curr == null) {
0534: return new CsmTypedef[0];
0535: }
0536:
0537: int arrayDepth = 0;
0538: AST nameToken = null;
0539: AST ptrOperator = null;
0540: String name = "";
0541: for (curr = curr.getNextSibling(); curr != null; curr = curr
0542: .getNextSibling()) {
0543: switch (curr.getType()) {
0544: case CPPTokenTypes.CSM_PTR_OPERATOR:
0545: // store only 1-st one - the others (if any) follows,
0546: // so it's TypeImpl.createType() responsibility to process them all
0547: if (ptrOperator == null) {
0548: ptrOperator = ast;
0549: }
0550: break;
0551: case CPPTokenTypes.CSM_QUALIFIED_ID:
0552: nameToken = curr;
0553: //token t = nameToken.
0554: name = AstUtil.findId(nameToken);
0555: //name = token.getText();
0556: break;
0557: case CPPTokenTypes.LSQUARE:
0558: arrayDepth++;
0559: case CPPTokenTypes.COMMA:
0560: case CPPTokenTypes.SEMICOLON:
0561: TypeImpl typeImpl = TypeFactory.createType(cls,
0562: ptrOperator, arrayDepth, ast, file);
0563: CsmTypedef typedef = createTypedef(
0564: (nameToken == null) ? ast : nameToken,
0565: file, container, typeImpl, name);
0566: if (cls != null && cls.getName().length() == 0) {
0567: ((TypedefImpl) typedef).setTypeUnnamed();
0568: }
0569: if (typedef != null) {
0570: if (cls instanceof ClassEnumBase) {
0571: ((ClassEnumBase) cls)
0572: .addEnclosingTypedef(typedef);
0573: }
0574: results.add(typedef);
0575: }
0576: ptrOperator = null;
0577: name = "";
0578: nameToken = null;
0579: arrayDepth = 0;
0580: break;
0581: }
0582:
0583: }
0584: break;
0585: default:
0586: // error message??
0587: }
0588: }
0589: return results.toArray(new CsmTypedef[results.size()]);
0590: }
0591:
0592: protected CsmTypedef[] renderTypedef(AST ast, FileImpl file,
0593: CsmObject container) {
0594: List<CsmTypedef> results = new ArrayList<CsmTypedef>();
0595: if (ast != null) {
0596: AST firstChild = ast.getFirstChild();
0597: if (firstChild.getType() == CPPTokenTypes.LITERAL_typedef) {
0598: //return createTypedef(ast, file, container);
0599:
0600: AST classifier = null;
0601: int arrayDepth = 0;
0602: AST nameToken = null;
0603: AST ptrOperator = null;
0604: String name = "";
0605:
0606: EnumImpl ei = null;
0607:
0608: for (AST curr = ast.getFirstChild(); curr != null; curr = curr
0609: .getNextSibling()) {
0610: switch (curr.getType()) {
0611: case CPPTokenTypes.CSM_TYPE_COMPOUND:
0612: case CPPTokenTypes.CSM_TYPE_BUILTIN:
0613: classifier = curr;
0614: break;
0615: case CPPTokenTypes.LITERAL_enum:
0616: if (AstUtil.findSiblingOfType(curr,
0617: CPPTokenTypes.RCURLY) != null) {
0618: if (container instanceof CsmScope) {
0619: ei = EnumImpl.create(curr,
0620: (CsmScope) container, file);
0621: if (container instanceof MutableDeclarationsContainer)
0622: ((MutableDeclarationsContainer) container)
0623: .addDeclaration(ei);
0624: }
0625: break;
0626: }
0627: // else fall through!
0628: case CPPTokenTypes.LITERAL_struct:
0629: case CPPTokenTypes.LITERAL_union:
0630: case CPPTokenTypes.LITERAL_class:
0631: AST next = curr.getNextSibling();
0632: if (next != null
0633: && next.getType() == CPPTokenTypes.CSM_QUALIFIED_ID) {
0634: classifier = next;
0635: }
0636: break;
0637: case CPPTokenTypes.CSM_PTR_OPERATOR:
0638: // store only 1-st one - the others (if any) follows,
0639: // so it's TypeImpl.createType() responsibility to process them all
0640: if (ptrOperator == null) {
0641: ptrOperator = curr;
0642: }
0643: break;
0644: case CPPTokenTypes.CSM_QUALIFIED_ID:
0645: // now token corresponds the name, since the case "struct S" is processed before
0646: nameToken = curr;
0647: name = AstUtil.findId(nameToken);
0648: break;
0649: case CPPTokenTypes.LSQUARE:
0650: arrayDepth++;
0651: break;
0652: case CPPTokenTypes.COMMA:
0653: case CPPTokenTypes.SEMICOLON:
0654: TypeImpl typeImpl = null;
0655: if (classifier != null) {
0656: typeImpl = TypeFactory.createType(
0657: classifier, file, ptrOperator,
0658: arrayDepth);
0659: } else if (ei != null) {
0660: typeImpl = TypeFactory.createType(ei,
0661: ptrOperator, arrayDepth, ast, file);
0662: }
0663: if (typeImpl != null) {
0664: CsmTypedef typedef = createTypedef(
0665: ast/*nameToken*/, file, container,
0666: typeImpl, name);
0667: if (typedef != null) {
0668: if (ei != null
0669: && ei.getName().length() == 0) {
0670: ((TypedefImpl) typedef)
0671: .setTypeUnnamed();
0672: }
0673: results.add(typedef);
0674: if (classifier instanceof ClassEnumBase) {
0675: ((ClassEnumBase) classifier)
0676: .addEnclosingTypedef(typedef);
0677: } else if (ei instanceof ClassEnumBase) {
0678: ((ClassEnumBase) ei)
0679: .addEnclosingTypedef(typedef);
0680: }
0681: }
0682: }
0683: ptrOperator = null;
0684: name = "";
0685: nameToken = null;
0686: arrayDepth = 0;
0687: break;
0688: }
0689: }
0690: }
0691: }
0692: return results.toArray(new CsmTypedef[results.size()]);
0693: }
0694:
0695: protected CsmTypedef createTypedef(AST ast, FileImpl file,
0696: CsmObject container, CsmType type, String name) {
0697: return new TypedefImpl(ast, file, container, type, name);
0698: }
0699:
0700: public static boolean renderForwardClassDeclaration(AST ast,
0701: NamespaceImpl currentNamespace,
0702: MutableDeclarationsContainer container, FileImpl file) {
0703:
0704: AST child = ast.getFirstChild();
0705: if (child == null) {
0706: return false;
0707: }
0708: if (child.getType() == CPPTokenTypes.LITERAL_template) {
0709: child = child.getNextSibling();
0710: if (child == null) {
0711: return false;
0712: }
0713: }
0714:
0715: switch (child.getType()) {
0716: case CPPTokenTypes.LITERAL_class:
0717: case CPPTokenTypes.LITERAL_struct:
0718: case CPPTokenTypes.LITERAL_union:
0719: ClassForwardDeclarationImpl cfdi = new ClassForwardDeclarationImpl(
0720: ast, file);
0721: if (container != null) {
0722: container.addDeclaration(cfdi);
0723: }
0724: return true;
0725: }
0726:
0727: return false;
0728: }
0729:
0730: public static boolean renderForwardMemberDeclaration(AST ast,
0731: NamespaceImpl currentNamespace,
0732: MutableDeclarationsContainer container, FileImpl file) {
0733:
0734: AST child = ast.getFirstChild();
0735: while (child != null) {
0736: switch (child.getType()) {
0737: case CPPTokenTypes.LITERAL_template:
0738: case CPPTokenTypes.LITERAL_inline:
0739: child = child.getNextSibling();
0740: continue;
0741: }
0742: break;
0743: }
0744: if (child == null) {
0745: return false;
0746: }
0747: if (child.getType() == CPPTokenTypes.LITERAL_template) {
0748: child = child.getNextSibling();
0749: if (child == null) {
0750: return false;
0751: }
0752: }
0753:
0754: switch (child.getType()) {
0755: case CPPTokenTypes.CSM_TYPE_COMPOUND:
0756: case CPPTokenTypes.CSM_TYPE_BUILTIN:
0757: child = child.getNextSibling();
0758: if (child != null) {
0759: if (child.getType() == CPPTokenTypes.CSM_VARIABLE_DECLARATION) {
0760: //static variable definition
0761: } else {
0762: //method forward declaratin
0763: FunctionImpl ftdecl = new FunctionImpl(ast, file,
0764: currentNamespace);
0765: if (container != null) {
0766: container.addDeclaration(ftdecl);
0767: }
0768: return true;
0769: }
0770: }
0771: break;
0772: }
0773:
0774: return false;
0775: }
0776:
0777: public static CharSequence getQualifiedName(AST qid) {
0778: if (qid != null
0779: && qid.getType() == CPPTokenTypes.CSM_QUALIFIED_ID) {
0780: if (qid.getFirstChild() != null) {
0781: StringBuilder sb = new StringBuilder();
0782: for (AST namePart = qid.getFirstChild(); namePart != null; namePart = namePart
0783: .getNextSibling()) {
0784: // TODO: update this assert it should accept names like: allocator<char, typename A>
0785: // if( ! ( namePart.getType() == CPPTokenTypes.ID || namePart.getType() == CPPTokenTypes.SCOPE ||
0786: // namePart.getType() == CPPTokenTypes.LESSTHAN || namePart.getType() == CPPTokenTypes.GREATERTHAN ||
0787: // namePart.getType() == CPPTokenTypes.CSM_TYPE_BUILTIN || namePart.getType() == CPPTokenTypes.CSM_TYPE_COMPOUND ||
0788: // namePart.getType() == CPPTokenTypes.COMMA) ) {
0789: // new Exception("Unexpected token type " + namePart).printStackTrace(System.err);
0790: // }
0791: if (namePart.getType() == CPPTokenTypes.CSM_TYPE_BUILTIN) {
0792: AST builtInType = namePart.getFirstChild();
0793: sb.append(builtInType != null ? builtInType
0794: .getText() : "");
0795: } else {
0796: sb.append(namePart.getText());
0797: }
0798: }
0799: return TextCache.getString(sb.toString());
0800: }
0801: }
0802: return "";
0803: }
0804:
0805: public static String[] getNameTokens(AST qid) {
0806: if (qid != null
0807: && (qid.getType() == CPPTokenTypes.CSM_QUALIFIED_ID || qid
0808: .getType() == CPPTokenTypes.CSM_TYPE_COMPOUND)) {
0809: int templateDepth = 0;
0810: if (qid.getNextSibling() != null) {
0811: List<String> l = new ArrayList<String>();
0812: for (AST namePart = qid.getFirstChild(); namePart != null; namePart = namePart
0813: .getNextSibling()) {
0814: if (templateDepth == 0
0815: && namePart.getType() == CPPTokenTypes.ID) {
0816: l.add(namePart.getText());
0817: } else if (namePart.getType() == CPPTokenTypes.LESSTHAN) {
0818: // the beginning of template parameters
0819: templateDepth++;
0820: } else if (namePart.getType() == CPPTokenTypes.GREATERTHAN) {
0821: // the beginning of template parameters
0822: templateDepth--;
0823: } else {
0824: //assert namePart.getType() == CPPTokenTypes.SCOPE;
0825: if (templateDepth == 0
0826: && namePart.getType() != CPPTokenTypes.SCOPE) {
0827: StringBuilder tokenText = new StringBuilder();
0828: tokenText.append('[').append(
0829: namePart.getText());
0830: if (namePart.getNumberOfChildren() == 0) {
0831: tokenText.append(", line=").append(
0832: namePart.getLine()); // NOI18N
0833: tokenText.append(", column=").append(
0834: namePart.getColumn()); // NOI18N
0835: }
0836: tokenText.append(']');
0837: System.err
0838: .println("Incorect token: expected '::', found "
0839: + tokenText.toString());
0840: }
0841: }
0842: }
0843: return l.toArray(new String[l.size()]);
0844: }
0845: }
0846: return new String[0];
0847: }
0848:
0849: public static TypeImpl renderType(AST tokType, CsmFile file) {
0850:
0851: AST typeAST = tokType;
0852: tokType = getFirstSiblingSkipQualifiers(tokType);
0853:
0854: if (tokType == null
0855: || (tokType.getType() != CPPTokenTypes.CSM_TYPE_BUILTIN && tokType
0856: .getType() != CPPTokenTypes.CSM_TYPE_COMPOUND)) {
0857: return null;
0858: }
0859:
0860: /**
0861: CsmClassifier classifier = null;
0862: if( tokType.getType() == CPPTokenTypes.CSM_TYPE_BUILTIN ) {
0863: classifier = BuiltinTypes.getBuiltIn(tokType);
0864: }
0865: else { // tokType.getType() == CPPTokenTypes.CSM_TYPE_COMPOUND
0866: try {
0867: Resolver resolver = new Resolver(file, ((CsmAST) tokType.getFirstChild()).getOffset());
0868: // gather name components into string array
0869: // for example, for std::vector new String[] { "std", "vector" }
0870: List l = new ArrayList();
0871: for( AST namePart = tokType.getFirstChild(); namePart != null; namePart = namePart.getNextSibling() ) {
0872: if( namePart.getType() == CPPTokenTypes.ID ) {
0873: l.add(namePart.getText());
0874: }
0875: else {
0876: assert namePart.getType() == CPPTokenTypes.SCOPE;
0877: }
0878: }
0879: CsmObject o = resolver.resolve((String[]) l.toArray(new String[l.size()]));
0880: if( o instanceof CsmClassifier ) {
0881: classifier = (CsmClassifier) o;
0882: }
0883: }
0884: catch( Exception e ) {
0885: e.printStackTrace(System.err);
0886: }
0887: }
0888:
0889: if( classifier != null ) {
0890: AST next = tokType.getNextSibling();
0891: AST ptrOperator = (next != null && next.getType() == CPPTokenTypes.CSM_PTR_OPERATOR) ? next : null;
0892: return TypeImpl.createType(classifier, ptrOperator, 0);
0893: }
0894:
0895: return null;
0896: */
0897: AST next = tokType.getNextSibling();
0898: AST ptrOperator = (next != null && next.getType() == CPPTokenTypes.CSM_PTR_OPERATOR) ? next
0899: : null;
0900: return TypeFactory.createType(typeAST/*tokType*/, file,
0901: ptrOperator, 0);
0902: }
0903:
0904: /**
0905: * Returns first sibling (or just passed ast), skipps cv-qualifiers and storage class specifiers
0906: */
0907: public static AST getFirstSiblingSkipQualifiers(AST ast) {
0908: while (ast != null && isQualifier(ast.getType())) {
0909: ast = ast.getNextSibling();
0910: }
0911: return ast;
0912: }
0913:
0914: /**
0915: * Returns first child, skipps cv-qualifiers and storage class specifiers
0916: */
0917: public static AST getFirstChildSkipQualifiers(AST ast) {
0918: return getFirstSiblingSkipQualifiers(ast.getFirstChild());
0919: }
0920:
0921: public static boolean isQualifier(int tokenType) {
0922: return isCVQualifier(tokenType)
0923: || isStorageClassSpecifier(tokenType);
0924: }
0925:
0926: public static boolean isCVQualifier(int tokenType) {
0927: return isConstQualifier(tokenType)
0928: || isVolatileQualifier(tokenType);
0929: }
0930:
0931: public static boolean isConstQualifier(int tokenType) {
0932: switch (tokenType) {
0933: case CPPTokenTypes.LITERAL_const:
0934: return true;
0935: case CPPTokenTypes.LITERAL___const:
0936: return true;
0937: default:
0938: return false;
0939: }
0940: }
0941:
0942: public static boolean isVolatileQualifier(int tokenType) {
0943: switch (tokenType) {
0944: case CPPTokenTypes.LITERAL_volatile:
0945: return true;
0946: case CPPTokenTypes.LITERAL___volatile__:
0947: return true;
0948: default:
0949: return false;
0950: }
0951: }
0952:
0953: public static boolean isStorageClassSpecifier(int tokenType) {
0954: switch (tokenType) {
0955: case CPPTokenTypes.LITERAL_auto:
0956: return true;
0957: case CPPTokenTypes.LITERAL_register:
0958: return true;
0959: case CPPTokenTypes.LITERAL_static:
0960: return true;
0961: case CPPTokenTypes.LITERAL_extern:
0962: return true;
0963: case CPPTokenTypes.LITERAL_mutable:
0964: return true;
0965: default:
0966: return false;
0967: }
0968: }
0969:
0970: /**
0971: * Checks whether the given AST is a variable declaration(s),
0972: * if yes, creates variable(s), adds to conteiner(s), returns true,
0973: * otherwise returns false;
0974: *
0975: * There might be two containers, in which the given variable should be added.
0976: * For example, global variables should beadded both to file and to global namespace;
0977: * variables, declared in some namespace definition, should be added to both this definition and correspondent namespace as well.
0978: *
0979: * On the other hand, local variables are added only to it's containing scope, so either container1 or container2 might be null.
0980: *
0981: * @param ast AST to process
0982: * @param container1 container to add created variable into (may be null)
0983: * @param container2 container to add created variable into (may be null)
0984: */
0985: public boolean renderVariable(AST ast,
0986: MutableDeclarationsContainer namespaceContainer,
0987: MutableDeclarationsContainer container2) {
0988: boolean _static = AstUtil.hasChildOfType(ast,
0989: CPPTokenTypes.LITERAL_static);
0990: AST typeAST = ast.getFirstChild();
0991: AST tokType = getFirstChildSkipQualifiers(ast);
0992: if (tokType == null) {
0993: return false;
0994: }
0995: boolean isThisReference = false;
0996: if (tokType != null
0997: && tokType.getType() == CPPTokenTypes.LITERAL_struct
0998: || tokType.getType() == CPPTokenTypes.LITERAL_union
0999: || tokType.getType() == CPPTokenTypes.LITERAL_enum
1000: || tokType.getType() == CPPTokenTypes.LITERAL_class) {
1001: // This is struct/class word for reference on containing struct/class
1002: tokType = tokType.getNextSibling();
1003: typeAST = tokType;
1004: if (tokType == null) {
1005: return false;
1006: }
1007: isThisReference = true;
1008: }
1009: if (tokType != null && isConstQualifier(tokType.getType())) {
1010: assert (false) : "must be skipped above";
1011: tokType = tokType.getNextSibling();
1012: }
1013:
1014: if (tokType.getType() == CPPTokenTypes.CSM_TYPE_BUILTIN
1015: || tokType.getType() == CPPTokenTypes.CSM_TYPE_COMPOUND
1016: || tokType.getType() == CPPTokenTypes.CSM_QUALIFIED_ID
1017: && isThisReference) {
1018:
1019: AST nextToken = tokType.getNextSibling();
1020: while (nextToken != null
1021: && (nextToken.getType() == CPPTokenTypes.CSM_PTR_OPERATOR
1022: || isQualifier(nextToken.getType()) || nextToken
1023: .getType() == CPPTokenTypes.LPAREN)) {
1024: nextToken = nextToken.getNextSibling();
1025: }
1026:
1027: if (nextToken == null
1028: || nextToken.getType() == CPPTokenTypes.LSQUARE
1029: || nextToken.getType() == CPPTokenTypes.CSM_VARIABLE_DECLARATION
1030: || nextToken.getType() == CPPTokenTypes.CSM_ARRAY_DECLARATION
1031: || nextToken.getType() == CPPTokenTypes.ASSIGNEQUAL) {
1032:
1033: AST ptrOperator = null;
1034: boolean theOnly = true;
1035: boolean hasVariables = false;
1036: int inParamsLevel = 0;
1037:
1038: for (AST token = ast.getFirstChild(); token != null; token = token
1039: .getNextSibling()) {
1040: switch (token.getType()) {
1041: case CPPTokenTypes.LPAREN:
1042: inParamsLevel++;
1043: break;
1044: case CPPTokenTypes.RPAREN:
1045: inParamsLevel--;
1046: break;
1047: case CPPTokenTypes.CSM_PTR_OPERATOR:
1048: // store only 1-st one - the others (if any) follows,
1049: // so it's TypeImpl.createType() responsibility to process them all
1050: if (ptrOperator == null && inParamsLevel == 0) {
1051: ptrOperator = token;
1052: }
1053: break;
1054: case CPPTokenTypes.CSM_VARIABLE_DECLARATION:
1055: case CPPTokenTypes.CSM_ARRAY_DECLARATION:
1056: hasVariables = true;
1057: if (theOnly) {
1058: for (AST next = token.getNextSibling(); next != null; next = next
1059: .getNextSibling()) {
1060: int type = next.getType();
1061: if (type == CPPTokenTypes.CSM_VARIABLE_DECLARATION
1062: || type == CPPTokenTypes.CSM_ARRAY_DECLARATION) {
1063: theOnly = false;
1064: }
1065: }
1066: }
1067: processVariable(token, ptrOperator,
1068: (theOnly ? ast : token),
1069: typeAST/*tokType*/,
1070: namespaceContainer, container2, file,
1071: _static);
1072: ptrOperator = null;
1073: break;
1074: }
1075: }
1076: if (!hasVariables) {
1077: // unnamed parameter
1078: processVariable(ast, ptrOperator, ast,
1079: typeAST/*tokType*/, namespaceContainer,
1080: container2, file, _static);
1081: }
1082: return true;
1083: }
1084: }
1085: return false;
1086: }
1087:
1088: protected void processVariable(AST varAst, AST ptrOperator,
1089: AST offsetAst, AST classifier,
1090: MutableDeclarationsContainer container1,
1091: MutableDeclarationsContainer container2, FileImpl file,
1092: boolean _static) {
1093: int arrayDepth = 0;
1094: String name = "";
1095: AST qn = null;
1096: int inParamsLevel = 0;
1097: for (AST token = varAst.getFirstChild(); token != null; token = token
1098: .getNextSibling()) {
1099: switch (token.getType()) {
1100: case CPPTokenTypes.LPAREN:
1101: inParamsLevel++;
1102: break;
1103: case CPPTokenTypes.RPAREN:
1104: inParamsLevel--;
1105: break;
1106: case CPPTokenTypes.LSQUARE:
1107: if (inParamsLevel == 0) {
1108: arrayDepth++;
1109: }
1110: break;
1111: case CPPTokenTypes.LITERAL_struct:
1112: case CPPTokenTypes.LITERAL_union:
1113: case CPPTokenTypes.LITERAL_enum:
1114: case CPPTokenTypes.LITERAL_class:
1115: // skip both this and next
1116: token = token.getNextSibling();
1117: continue;
1118: case CPPTokenTypes.CSM_QUALIFIED_ID:
1119: if (inParamsLevel == 0) {
1120: qn = token;
1121: }
1122: // no break;
1123: case CPPTokenTypes.ID:
1124: if (inParamsLevel == 0) {
1125: name = token.getText();
1126: }
1127: break;
1128: }
1129: }
1130: CsmType type = TypeFactory.createType(classifier, file,
1131: ptrOperator, arrayDepth);
1132: if (isScopedId(qn)) {
1133: // This is definition of global namespace variable or definition of static class variable
1134: // TODO What about global variable definitions:
1135: // extern int i; - declaration
1136: // int i; - definition
1137: VariableDefinitionImpl var = new VariableDefinitionImpl(
1138: offsetAst, file, type, name);
1139: var.setStatic(_static);
1140: if (container2 != null) {
1141: container2.addDeclaration(var);
1142: }
1143: } else {
1144: VariableImpl var = createVariable(offsetAst, file, type,
1145: name, _static, container1, container2, null);
1146: if (container2 != null) {
1147: container2.addDeclaration(var);
1148: }
1149: // TODO! don't add to namespace if....
1150: if (container1 != null) {
1151: container1.addDeclaration(var);
1152: }
1153: }
1154: }
1155:
1156: protected VariableImpl createVariable(AST offsetAst, CsmFile file,
1157: CsmType type, String name, boolean _static,
1158: MutableDeclarationsContainer container1,
1159: MutableDeclarationsContainer container2, CsmScope scope) {
1160:
1161: VariableImpl var = new VariableImpl(offsetAst, file, type,
1162: name, scope, (container1 != null)
1163: || (container2 != null));
1164: var.setStatic(_static);
1165: return var;
1166: }
1167:
1168: public static List<CsmParameter> renderParameters(AST ast,
1169: final CsmFile file, CsmScope scope) {
1170: List<CsmParameter> parameters = new ArrayList<CsmParameter>();
1171: if (ast != null
1172: && (ast.getType() == CPPTokenTypes.CSM_PARMLIST || ast
1173: .getType() == CPPTokenTypes.CSM_KR_PARMLIST)) {
1174: for (AST token = ast.getFirstChild(); token != null; token = token
1175: .getNextSibling()) {
1176: if (token.getType() == CPPTokenTypes.CSM_PARAMETER_DECLARATION) {
1177: List<ParameterImpl> params = AstRenderer
1178: .renderParameter(token, file, scope);
1179: if (params != null) {
1180: parameters.addAll(params);
1181: }
1182: }
1183: }
1184: }
1185: return parameters;
1186: }
1187:
1188: public static boolean isVoidParameter(AST ast) {
1189: if (ast != null
1190: && (ast.getType() == CPPTokenTypes.CSM_PARMLIST || ast
1191: .getType() == CPPTokenTypes.CSM_KR_PARMLIST)) {
1192: AST token = ast.getFirstChild();
1193: if (token != null
1194: && token.getType() == CPPTokenTypes.CSM_PARAMETER_DECLARATION) {
1195: AST firstChild = token.getFirstChild();
1196: if (firstChild != null) {
1197: if (firstChild.getType() == CPPTokenTypes.CSM_TYPE_BUILTIN
1198: && firstChild.getNextSibling() == null) {
1199: AST grandChild = firstChild.getFirstChild();
1200: if (grandChild != null
1201: && grandChild.getType() == CPPTokenTypes.LITERAL_void) {
1202: return true;
1203: }
1204: }
1205: }
1206: }
1207: }
1208: return false;
1209: }
1210:
1211: public static List<ParameterImpl> renderParameter(AST ast,
1212: final CsmFile file, final CsmScope scope1) {
1213:
1214: // The only reason there might be several declarations is the K&R C style
1215: // we can split this function into two (for K&R and "normal" parameters)
1216: // if we found this ineffective; but now I vote for more clear and readable - i.e. single for both cases - code
1217:
1218: final List<ParameterImpl> result = new ArrayList<ParameterImpl>();
1219: AST firstChild = ast.getFirstChild();
1220: if (firstChild != null) {
1221: if (firstChild.getType() == CPPTokenTypes.ELLIPSIS) {
1222: ParameterImpl parameter = new ParameterImpl(ast
1223: .getFirstChild(), file, null, "...", scope1); // NOI18N
1224: result.add(parameter);
1225: return result;
1226: }
1227: if (firstChild.getType() == CPPTokenTypes.CSM_TYPE_BUILTIN
1228: && firstChild.getNextSibling() == null) {
1229: AST grandChild = firstChild.getFirstChild();
1230: if (grandChild != null
1231: && grandChild.getType() == CPPTokenTypes.LITERAL_void) {
1232: return Collections.emptyList();
1233: }
1234: }
1235: }
1236: class AstRendererEx extends AstRenderer {
1237: public AstRendererEx() {
1238: super ((FileImpl) file);
1239: }
1240:
1241: @Override
1242: protected VariableImpl createVariable(AST offsetAst,
1243: CsmFile file, CsmType type, String name,
1244: boolean _static,
1245: MutableDeclarationsContainer container1,
1246: MutableDeclarationsContainer container2,
1247: CsmScope scope2) {
1248: type = TemplateUtils.checkTemplateType(type, scope1);
1249: ParameterImpl parameter = new ParameterImpl(offsetAst,
1250: file, type, name, scope1);
1251: result.add(parameter);
1252: return parameter;
1253: }
1254: }
1255: AstRendererEx renderer = new AstRendererEx();
1256: renderer.renderVariable(ast, null, null);
1257: return result;
1258: }
1259:
1260: // public static boolean isCsmType(AST token) {
1261: // if( token != null ) {
1262: // int type = token.getType();
1263: // return type == CPPTokenTypes.CSM_TYPE_BUILTIN || type == CPPTokenTypes.CSM_TYPE_COMPOUND;
1264: // }
1265: // return false;
1266: // }
1267:
1268: public static int getType(AST token) {
1269: return (token == null) ? -1 : token.getType();
1270: }
1271:
1272: public static int getFirstChildType(AST token) {
1273: AST child = token.getFirstChild();
1274: return (child == null) ? -1 : child.getType();
1275: }
1276:
1277: // public static int getNextSiblingType(AST token) {
1278: // AST sibling = token.getNextSibling();
1279: // return (sibling == null) ? -1 : sibling.getType();
1280: // }
1281:
1282: public static boolean renderNSP(AST token,
1283: NamespaceImpl currentNamespace,
1284: MutableDeclarationsContainer container, FileImpl file) {
1285: token = token.getFirstChild();
1286: if (token == null)
1287: return false;
1288: switch (token.getType()) {
1289: case CPPTokenTypes.CSM_NAMESPACE_ALIAS:
1290: container
1291: .addDeclaration(new NamespaceAliasImpl(token, file));
1292: return true;
1293: case CPPTokenTypes.CSM_USING_DIRECTIVE:
1294: container
1295: .addDeclaration(new UsingDirectiveImpl(token, file));
1296: return true;
1297: case CPPTokenTypes.CSM_USING_DECLARATION:
1298: container.addDeclaration(new UsingDeclarationImpl(token,
1299: file));
1300: return true;
1301: }
1302: return false;
1303: }
1304:
1305: private boolean isClassSpecialization(AST ast) {
1306: AST type = ast.getFirstChild(); // type
1307: if (type != null) {
1308: AST child = type;
1309: while ((child = child.getNextSibling()) != null) {
1310: if (child.getType() == CPPTokenTypes.GREATERTHAN) {
1311: child = child = child.getNextSibling();
1312: if (child != null
1313: && (child.getType() == CPPTokenTypes.LITERAL_class || child
1314: .getType() == CPPTokenTypes.LITERAL_struct)) {
1315: return true;
1316: }
1317: return false;
1318: }
1319: }
1320: }
1321: return true;
1322: }
1323:
1324: protected boolean isMemberDefinition(AST ast) {
1325: if (CastUtils.isCast(ast)) {
1326: return CastUtils.isMemberDefinition(ast);
1327: }
1328: AST id = AstUtil.findMethodName(ast);
1329: return isScopedId(id);
1330: }
1331:
1332: private boolean isScopedId(AST id) {
1333: if (id == null) {
1334: return false;
1335: }
1336: if (id.getType() == CPPTokenTypes.ID) {
1337: AST scope = id.getNextSibling();
1338: if (scope != null && scope.getType() == CPPTokenTypes.SCOPE) {
1339: return true;
1340: }
1341: } else if (id.getType() == CPPTokenTypes.CSM_QUALIFIED_ID) {
1342: int i = 0;
1343: AST q = id.getFirstChild();
1344: while (q != null) {
1345: if (q.getType() == CPPTokenTypes.SCOPE) {
1346: return true;
1347: }
1348: q = q.getNextSibling();
1349: }
1350: }
1351: return false;
1352: }
1353:
1354: public static CsmCompoundStatement findCompoundStatement(AST ast,
1355: CsmFile file, CsmFunction owner) {
1356: for (AST token = ast.getFirstChild(); token != null; token = token
1357: .getNextSibling()) {
1358: switch (token.getType()) {
1359: case CPPTokenTypes.CSM_COMPOUND_STATEMENT:
1360: return new CompoundStatementImpl(token, file, owner);
1361: case CPPTokenTypes.CSM_COMPOUND_STATEMENT_LAZY:
1362: return new LazyCompoundStatementImpl(token, file, owner);
1363: }
1364: }
1365: // prevent null bodies
1366: return new EmptyCompoundStatementImpl(ast, file, owner);
1367: }
1368:
1369: public static StatementBase renderStatement(AST ast, CsmFile file,
1370: CsmScope scope) {
1371: switch (ast.getType()) {
1372: case CPPTokenTypes.CSM_LABELED_STATEMENT:
1373: return new LabelImpl(ast, file, scope);
1374: case CPPTokenTypes.CSM_CASE_STATEMENT:
1375: return new CaseStatementImpl(ast, file, scope);
1376: case CPPTokenTypes.CSM_DEFAULT_STATEMENT:
1377: return new UniversalStatement(ast, file,
1378: CsmStatement.Kind.DEFAULT, scope);
1379: case CPPTokenTypes.CSM_EXPRESSION_STATEMENT:
1380: return new ExpressionStatementImpl(ast, file, scope);
1381: case CPPTokenTypes.CSM_CLASS_DECLARATION:
1382: case CPPTokenTypes.CSM_ENUM_DECLARATION:
1383: case CPPTokenTypes.CSM_DECLARATION_STATEMENT:
1384: case CPPTokenTypes.CSM_GENERIC_DECLARATION:
1385: return new DeclarationStatementImpl(ast, file, scope);
1386: case CPPTokenTypes.CSM_COMPOUND_STATEMENT:
1387: return new CompoundStatementImpl(ast, file, scope);
1388: case CPPTokenTypes.CSM_IF_STATEMENT:
1389: return new IfStatementImpl(ast, file, scope);
1390: case CPPTokenTypes.CSM_SWITCH_STATEMENT:
1391: return new SwitchStatementImpl(ast, file, scope);
1392: case CPPTokenTypes.CSM_WHILE_STATEMENT:
1393: return new LoopStatementImpl(ast, file, false, scope);
1394: case CPPTokenTypes.CSM_DO_WHILE_STATEMENT:
1395: return new LoopStatementImpl(ast, file, true, scope);
1396: case CPPTokenTypes.CSM_FOR_STATEMENT:
1397: return new ForStatementImpl(ast, file, scope);
1398: case CPPTokenTypes.CSM_GOTO_STATEMENT:
1399: return new GotoStatementImpl(ast, file, scope);
1400: case CPPTokenTypes.CSM_CONTINUE_STATEMENT:
1401: return new UniversalStatement(ast, file,
1402: CsmStatement.Kind.CONTINUE, scope);
1403: case CPPTokenTypes.CSM_BREAK_STATEMENT:
1404: return new UniversalStatement(ast, file,
1405: CsmStatement.Kind.BREAK, scope);
1406: case CPPTokenTypes.CSM_RETURN_STATEMENT:
1407: return new ReturnStatementImpl(ast, file, scope);
1408: case CPPTokenTypes.CSM_TRY_STATEMENT:
1409: return new TryCatchStatementImpl(ast, file, scope);
1410: case CPPTokenTypes.CSM_CATCH_CLAUSE:
1411: // TODO: isn't it in TryCatch ??
1412: return new UniversalStatement(ast, file,
1413: CsmStatement.Kind.CATCH, scope);
1414: case CPPTokenTypes.CSM_THROW_STATEMENT:
1415: // TODO: throw
1416: return new UniversalStatement(ast, file,
1417: CsmStatement.Kind.THROW, scope);
1418: case CPPTokenTypes.CSM_ASM_BLOCK:
1419: // just ignore
1420: break;
1421: // case CPPTokenTypes.SEMICOLON:
1422: // case CPPTokenTypes.LCURLY:
1423: // case CPPTokenTypes.RCURLY:
1424: // break;
1425: // default:
1426: // System.out.println("unexpected statement kind="+ast.getType());
1427: // break;
1428: }
1429: return null;
1430: }
1431:
1432: public ExpressionBase renderExpression(AST ast, CsmScope scope) {
1433: return isExpression(ast) ? new ExpressionBase(ast, file, null,
1434: scope) : null;
1435: }
1436:
1437: public CsmCondition renderCondition(AST ast, CsmScope scope) {
1438: if (ast != null && ast.getType() == CPPTokenTypes.CSM_CONDITION) {
1439: AST first = ast.getFirstChild();
1440: if (first != null) {
1441: int type = first.getType();
1442: if (isExpression(type)) {
1443: return new ConditionExpressionImpl(first, file,
1444: scope);
1445: } else if (type == CPPTokenTypes.CSM_TYPE_BUILTIN
1446: || type == CPPTokenTypes.CSM_TYPE_COMPOUND) {
1447: return new ConditionDeclarationImpl(ast, file,
1448: scope);
1449: }
1450: }
1451: }
1452: return null;
1453: }
1454:
1455: public static List<CsmExpression> renderConstructorInitializersList(
1456: AST ast, CsmScope scope, CsmFile file) {
1457: List<CsmExpression> initializers = null;
1458: for (AST token = ast.getFirstChild(); token != null; token = token
1459: .getNextSibling()) {
1460: if (token.getType() == CPPTokenTypes.CSM_CTOR_INITIALIZER_LIST) {
1461: for (AST initializerToken = token.getFirstChild(); initializerToken != null; initializerToken = initializerToken
1462: .getNextSibling()) {
1463: if (initializerToken.getType() == CPPTokenTypes.CSM_CTOR_INITIALIZER) {
1464: ExpressionBase initializer = new ExpressionBase(
1465: initializerToken, file, null, scope);
1466: if (initializers == null) {
1467: initializers = new ArrayList<CsmExpression>();
1468: }
1469: initializers.add(initializer);
1470: }
1471: }
1472: }
1473: }
1474: return initializers;
1475: }
1476:
1477: public static boolean isExpression(AST ast) {
1478: return ast != null && isExpression(ast.getType());
1479: }
1480:
1481: public static boolean isExpression(int tokenType) {
1482: return CPPTokenTypes.CSM_EXPRESSIONS_START < tokenType
1483: && tokenType < CPPTokenTypes.CSM_EXPRESSIONS_END;
1484: }
1485:
1486: public static boolean isStatement(AST ast) {
1487: return ast != null && isStatement(ast.getType());
1488: }
1489:
1490: public static boolean isStatement(int tokenType) {
1491: return CPPTokenTypes.CSM_STATEMENTS_START < tokenType
1492: && tokenType < CPPTokenTypes.CSM_STATEMENTS_END;
1493: }
1494:
1495: // public ExpressionBase renderExpression(ExpressionBase parent) {
1496: //
1497: // }
1498:
1499: }
|