/* * Created on Apr 4, 2007 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu * (jactr.org) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. This library is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU Lesser General Public License for more details. You should have * received a copy of the GNU Lesser General Public License along with this * library; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jactr.io.participant.impl; import java.util.Collection; import java.util.Map; import org.antlr.runtime.CommonToken; import org.antlr.runtime.tree.CommonTree; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.utils.IInstallable; import org.jactr.io.antlr3.builder.JACTRBuilder; import org.jactr.io.antlr3.misc.ASTSupport; import org.jactr.io.antlr3.misc.DetailedCommonTree; import org.jactr.io.participant.IASTInjector; /** * @author developer */ public class BasicASTInjector implements IASTInjector { /** * logger definition */ static private final Log LOGGER = LogFactory .getLog(BasicASTInjector.class); final private CommonTree _modelDescriptor; final private Class<? extends IInstallable> _participantClass; final private Map<String, String> _parameterMap; public BasicASTInjector(CommonTree modelDescriptor, Class<? extends IInstallable> participantClass, Map<String, String> parameterMap) { _modelDescriptor = modelDescriptor; /* * we no longer clear the locations since we cary the url of the origin, we * can more accurately differentiate local or imported nodes */ // if (_modelDescriptor != null) clearLocations(_modelDescriptor); _parameterMap = parameterMap; _participantClass = participantClass; } /** * @see org.jactr.io.participant.IASTInjector#inject(org.antlr.runtime.tree.CommonTree) */ public void inject(CommonTree modelDescriptor, boolean importBuffers) { importAll(_modelDescriptor, modelDescriptor, importBuffers); } public void injectParameters(CommonTree rootNode) { if (_parameterMap != null && _participantClass != null) { ASTSupport support = new ASTSupport(); for (Map.Entry<String, String> parameter : _parameterMap.entrySet()) support.setParameter(rootNode, parameter.getKey(), parameter.getValue(), false); // don't overwrite if it exists // already } } /** * import chunktypes from source to dest. If dest already contains a matching * (named) chunk-type, dest will be used instead and it will steal the chunks * from source. * * @param sourceDeclarativeMemory * @param destinationDeclarativeMemory */ static public void importChunkTypes(CommonTree sourceDeclarativeMemory, CommonTree destinationDeclarativeMemory) { // snag all the chuhnktypes Collection<CommonTree> importChunkTypes = ASTSupport.getTrees( sourceDeclarativeMemory, JACTRBuilder.CHUNK_TYPE); Map<String, CommonTree> destChunkTypes = ASTSupport.getMapOfTrees( destinationDeclarativeMemory, JACTRBuilder.CHUNK_TYPE); for (CommonTree chunkTypeTree : importChunkTypes) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Importing chunktypes " + chunkTypeTree.toStringTree()); String name = ASTSupport.getName(chunkTypeTree).toLowerCase(); CommonTree destChunkType = destChunkTypes.get(name); if (destChunkType != null) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Already have chunk type " + name + ", stealing children"); /* * lets replace the slots and parameters * @bug no. We want to keep the local version, replace the imported * one.. */ // steal(chunkTypeTree, destChunkType, JACTRBuilder.SLOTS); // steal(chunkTypeTree, destChunkType, JACTRBuilder.PARAMETERS); /* * and now the children */ CommonTree chunksWrapper = ASTSupport.getFirstDescendantWithType( destChunkType, JACTRBuilder.CHUNKS); Map<String, CommonTree> existingChunks = ASTSupport.getMapOfTrees( chunksWrapper, JACTRBuilder.CHUNK); Collection<CommonTree> chunksToSteal = ASTSupport.getTrees( chunkTypeTree, JACTRBuilder.CHUNK); for (CommonTree chunkToInsert : chunksToSteal) { String chunkName = ASTSupport.getName(chunkToInsert).toLowerCase(); if (!existingChunks.containsKey(chunkName)) { if (LOGGER.isDebugEnabled()) LOGGER.debug(name + " does not already have chunk " + chunkName + ", adding"); chunksWrapper.addChild(chunkToInsert); } else /* * we have to find the exact child, and replace it */ for (int i = 0; i < chunksWrapper.getChildCount(); i++) { CommonTree childToReplace = (CommonTree) chunksWrapper .getChild(i); if (ASTSupport.getName(childToReplace) .equalsIgnoreCase(chunkName)) { chunksWrapper.setChild(i, chunkToInsert); if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format( "Replaced %s at %d with imported version", chunkName, i)); } } } } else { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format( "%s doesn't already exist, importing entirely", name)); ASTSupport.addChunkType(destinationDeclarativeMemory, chunkTypeTree); } } if (LOGGER.isDebugEnabled()) LOGGER.debug("Contents of declarative " + ASTSupport.getFirstDescendantWithType(destinationDeclarativeMemory, JACTRBuilder.DECLARATIVE_MEMORY).toStringTree()); } private void steal(CommonTree srcTree, CommonTree destTree, int nodeType) { CommonTree toSteal = null; for (int i = 0; i < srcTree.getChildCount(); i++) if (srcTree.getChild(i).getType() == nodeType || nodeType == -1) { toSteal = (CommonTree) srcTree.getChild(i); break; } if (toSteal == null) return; for (int i = 0; i < destTree.getChildCount(); i++) if (destTree.getChild(i).getType() == nodeType || nodeType == -1) { destTree.setChild(i, toSteal); break; } } protected void importBuffers(CommonTree srcModel, CommonTree destModel) { // and buffers Map<String, CommonTree> importBuffers = ASTSupport.getMapOfTrees(srcModel, JACTRBuilder.BUFFER); CommonTree buffers = ASTSupport.getFirstDescendantWithType(destModel, JACTRBuilder.BUFFERS); Map<String, CommonTree> existingBuffers = ASTSupport.getMapOfTrees(buffers, JACTRBuilder.BUFFER); for (CommonTree bufferTree : importBuffers.values()) { String bufferName = ASTSupport.getName(bufferTree); if (LOGGER.isDebugEnabled()) LOGGER.debug("Importing buffer " + bufferTree.toStringTree()); CommonTree existingBuffer = existingBuffers.get(bufferName.toLowerCase()); if (existingBuffer == null) buffers.addChild(bufferTree); else { /* * if the local (dest) doesn't have any parameters, steal them. */ CommonTree originalParameters = ASTSupport.getFirstDescendantWithType( existingBuffer, JACTRBuilder.PARAMETERS); CommonTree newParameters = ASTSupport.getFirstDescendantWithType( bufferTree, JACTRBuilder.PARAMETERS); if ((originalParameters == null || originalParameters.getChildCount() == 0) && newParameters != null && newParameters.getChildCount() > 0) steal(newParameters, originalParameters, JACTRBuilder.PARAMETER); } } if (LOGGER.isDebugEnabled()) LOGGER.debug("Contents of BUFFERS : " + buffers.toStringTree()); } protected void importProductions(CommonTree srcModel, CommonTree destModel) { // and productions Map<String, CommonTree> importProductions = ASTSupport.getMapOfTrees( srcModel, JACTRBuilder.PRODUCTION); Map<String, CommonTree> currentProductions = ASTSupport.getMapOfTrees( destModel, JACTRBuilder.PRODUCTION); for (CommonTree productionTree : importProductions.values()) { String name = ASTSupport.getName(productionTree).toLowerCase(); if (!currentProductions.containsKey(name)) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Importing p " + productionTree.toStringTree()); ASTSupport.addProduction(destModel, productionTree); } else if (LOGGER.isDebugEnabled()) LOGGER.debug("Already contains production " + name); } if (LOGGER.isDebugEnabled()) LOGGER.debug("Contents of declarative " + ASTSupport.getFirstDescendantWithType(destModel, JACTRBuilder.PROCEDURAL_MEMORY).toStringTree()); } protected void importAll(CommonTree srcModel, CommonTree modelDescriptor, boolean importBuffers) { if (srcModel != null) { importChunkTypes(srcModel, modelDescriptor); importProductions(srcModel, modelDescriptor); if (importBuffers) importBuffers(srcModel, modelDescriptor); } } /** * clear the location information of imported nodes. * * @param root */ @Deprecated protected void clearLocations(CommonTree root) { if (root instanceof DetailedCommonTree) { ((DetailedCommonTree) root).setStartOffset(-1); ((DetailedCommonTree) root).setEndOffset(-1); } root.setTokenStartIndex(-1); root.setTokenStopIndex(-1); CommonToken token = (CommonToken) root.getToken(); if (token != null) { token.setLine(-1); token.setStartIndex(-1); token.setStopIndex(-1); token.setCharPositionInLine(-1); token.setTokenIndex(-1); } for (int i = 0; i < root.getChildCount(); i++) clearLocations((CommonTree) root.getChild(i)); } }