/******************************************************************************* * Copyright (c) 2005, 2017 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * *******************************************************************************/ package org.eclipse.dltk.tcl.internal.parser; import java.util.List; import org.eclipse.dltk.ast.ASTNode; import org.eclipse.dltk.ast.declarations.MethodDeclaration; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.ast.declarations.TypeDeclaration; import org.eclipse.dltk.ast.statements.Block; import org.eclipse.dltk.tcl.ast.TclModuleDeclaration; import org.eclipse.dltk.tcl.core.TclParseUtil; /** * * @author haiodo * */ public class TclASTBuilder { public static final int TYPE_MODULE = 0; public static final int TYPE_NAMESPACE = 1; public static final int TYPE_PROC = 2; public static final int TYPE_UNKNOWN = 3; private static void replaceChild(ASTNode node, ASTNode statement, ASTNode nsType) { if (node instanceof ModuleDeclaration) { List statements = ((ModuleDeclaration) node).getStatements(); int index = statements.indexOf(statement); statements.remove(index); statements.add(index, nsType); } else if (node instanceof TypeDeclaration) { List statements = ((TypeDeclaration) node).getStatements(); int index = statements.indexOf(statement); statements.remove(index); statements.add(index, nsType); } else if (node instanceof Block) { List statements = ((Block) node).getStatements(); int index = statements.indexOf(statement); statements.remove(index); statements.add(index, nsType); } } // Rebuild AST with corect type declarations and methods. public static void rebuildMethods(TclModuleDeclaration unit) { TypeDeclaration[] types = unit.getTypes(); if (types != null) { for (int i = 0; i < types.length; i++) { TypeDeclaration type = types[i]; rebuildMethodProcessBodies(type, unit); } } MethodDeclaration[] methods = unit.getFunctions(); if (methods != null) { // PatternLocator locator = getPatternLocator(); for (int i = 0; i < methods.length; i++) { MethodDeclaration method = methods[i]; if (method instanceof MethodDeclaration) { MethodDeclaration methodDeclaration = method; String name = methodDeclaration.getName(); if (name.indexOf("::") != -1) { if (name.startsWith("::")) { name = name.substring(2); } if (name.endsWith("::")) { name = name.substring(0, name.length() - 2); } name = name.replaceAll("(::)+", "::"); String[] split = TclParseUtil.tclSplit(name); methodDeclaration.setName(split[split.length - 1]); TypeDeclaration type = searchCreateTypeDeclaration(unit, split, method, 0); if (type != null) { unit.getStatements().remove(methodDeclaration); unit.getFunctionList().remove(methodDeclaration); type.getStatements().add(methodDeclaration); type.getMethodList().add(methodDeclaration); } } } } } } private static TypeDeclaration searchCreateTypeDeclaration( TclModuleDeclaration unit, String[] split, MethodDeclaration method, int offset) { if (split.length - 1 <= offset) { return null; } String typeName = split[0 + offset]; TypeDeclaration[] types = unit.getTypes(); for (int i = 0; i < types.length; i++) { if (types[i].getName().equals(typeName)) { return searchCreateTypeDeclaration(types[i], split, method, offset + 1); } } // not found, lets create one new. TypeDeclaration decl = new TypeDeclaration(typeName, method.getNameStart(), method.getNameEnd(), method.sourceStart(), method.sourceEnd()); unit.addStatement(decl); unit.getTypeList().add(decl); return searchCreateTypeDeclaration(decl, split, method, offset + 1); } private static TypeDeclaration searchCreateTypeDeclaration( TypeDeclaration typeDeclaration, String[] split, MethodDeclaration method, int offset) { if (offset == split.length - 1) { return typeDeclaration; } String typeName = split[0 + offset]; TypeDeclaration[] types = typeDeclaration.getTypes(); for (int i = 0; i < types.length; i++) { if (types[i].getName().equals(typeName)) { return searchCreateTypeDeclaration(types[i], split, method, offset + 1); } } // not found, lets create one new. TypeDeclaration decl = new TypeDeclaration(typeName, method.getNameStart(), method.getNameEnd(), method.sourceStart(), method.sourceEnd()); typeDeclaration.getStatements().add(decl); typeDeclaration.getTypeList().add(decl); return searchCreateTypeDeclaration(decl, split, method, offset + 1); } // Add functions to modules if then belong to top level elements. protected static void rebuildMethodProcessBodies(TypeDeclaration type, TclModuleDeclaration module) { MethodDeclaration[] methods = type.getMethods(); if (methods != null) { for (int i = 0; i < methods.length; i++) { MethodDeclaration method = methods[i]; if (method instanceof MethodDeclaration) { MethodDeclaration methodDeclaration = method; // TODO: Add support of internal to top level modifications. String name = methodDeclaration.getName(); if (name.indexOf("::") != -1) { boolean start = false; if (name.startsWith("::")) { name = name.substring(2); start = true; } if (name.endsWith("::")) { name = name.substring(0, name.length() - 2); } name = name.replaceAll("(::)+", "::"); String[] split = TclParseUtil.tclSplit(name); if (start && split.length > 2) { module.getFunctionList().add(methodDeclaration); type.getMethodList().remove(methodDeclaration); type.getStatements().remove(methodDeclaration); } else { method.setName(split[split.length - 1]); TypeDeclaration decl = searchCreateTypeDeclaration( type, split, method, 0); if (decl != null) { type.getMethodList().remove(methodDeclaration); type.getStatements().remove(methodDeclaration); decl.getStatements().add(method); decl.getMethodList().add(method); } } } } } } TypeDeclaration[] memberTypes = type.getTypes(); if (memberTypes != null) { for (int i = 0; i < memberTypes.length; i++) { TypeDeclaration memberType = memberTypes[i]; rebuildMethodProcessBodies(memberType, module); } } } }