1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 /* 21 * $Id: SymbolTable.java,v 1.5 2005/09/28 13:48:16 pvedula Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.compiler; 25 26 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType; 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.Stack; 32 import java.util.StringTokenizer; 33 34 /** 35 * @author Jacek Ambroziak 36 * @author Santiago Pericas-Geertsen 37 * @author Morten Jorgensen 38 * @LastModified: Oct 2017 39 */ 40 final class SymbolTable { 41 42 // These maps are used for all stylesheets 43 private final Map<String, Stylesheet> _stylesheets = new HashMap<>(); 44 private final Map<String, List<MethodType>> _primops = new HashMap<>(); 45 46 // These maps are used for some stylesheets 47 private Map<String, VariableBase> _variables = null; 48 private Map<String, Template> _templates = null; 49 private Map<String, AttributeSet> _attributeSets = null; 50 private Map<String, String> _aliases = null; 51 private Map<String, Integer> _excludedURI = null; 52 private Stack<Map<String, Integer>> _excludedURIStack = null; 53 private Map<String, DecimalFormatting> _decimalFormats = null; 54 private Map<String, Key> _keys = null; 55 56 public DecimalFormatting getDecimalFormatting(QName name) { 57 if (_decimalFormats == null) return null; 58 return(_decimalFormats.get(name.getStringRep())); 59 } 60 61 public void addDecimalFormatting(QName name, DecimalFormatting symbols) { 62 if (_decimalFormats == null) _decimalFormats = new HashMap<>(); 63 _decimalFormats.put(name.getStringRep(), symbols); 64 } 65 66 public Key getKey(QName name) { 67 if (_keys == null) return null; 68 return _keys.get(name.getStringRep()); 69 } 70 71 public void addKey(QName name, Key key) { 72 if (_keys == null) _keys = new HashMap<>(); 73 _keys.put(name.getStringRep(), key); 74 } 75 76 public Stylesheet addStylesheet(QName name, Stylesheet node) { 77 return _stylesheets.put(name.getStringRep(), node); 78 } 79 80 public Stylesheet lookupStylesheet(QName name) { 81 return _stylesheets.get(name.getStringRep()); 82 } 83 84 public Template addTemplate(Template template) { 85 final QName name = template.getName(); 86 if (_templates == null) _templates = new HashMap<>(); 87 return _templates.put(name.getStringRep(), template); 88 } 89 90 public Template lookupTemplate(QName name) { 91 if (_templates == null) return null; 92 return _templates.get(name.getStringRep()); 93 } 94 95 public Variable addVariable(Variable variable) { 96 if (_variables == null) _variables = new HashMap<>(); 97 final String name = variable.getName().getStringRep(); 98 return (Variable)_variables.put(name, variable); 99 } 100 101 public Param addParam(Param parameter) { 102 if (_variables == null) _variables = new HashMap<>(); 103 final String name = parameter.getName().getStringRep(); 104 return (Param)_variables.put(name, parameter); 105 } 106 107 public Variable lookupVariable(QName qname) { 108 if (_variables == null) return null; 109 final String name = qname.getStringRep(); 110 final VariableBase obj = _variables.get(name); 111 return obj instanceof Variable ? (Variable)obj : null; 112 } 113 114 public Param lookupParam(QName qname) { 115 if (_variables == null) return null; 116 final String name = qname.getStringRep(); 117 final VariableBase obj = _variables.get(name); 118 return obj instanceof Param ? (Param)obj : null; 119 } 120 121 public SyntaxTreeNode lookupName(QName qname) { 122 if (_variables == null) return null; 123 final String name = qname.getStringRep(); 124 return (SyntaxTreeNode)_variables.get(name); 125 } 126 127 public AttributeSet addAttributeSet(AttributeSet atts) { 128 if (_attributeSets == null) _attributeSets = new HashMap<>(); 129 return _attributeSets.put(atts.getName().getStringRep(), atts); 130 } 131 132 public AttributeSet lookupAttributeSet(QName name) { 133 if (_attributeSets == null) return null; 134 return _attributeSets.get(name.getStringRep()); 135 } 136 137 /** 138 * Add a primitive operator or function to the symbol table. To avoid 139 * name clashes with user-defined names, the prefix <tt>PrimopPrefix</tt> 140 * is prepended. 141 */ 142 public void addPrimop(String name, MethodType mtype) { 143 List<MethodType> methods = _primops.get(name); 144 if (methods == null) { 145 _primops.put(name, methods = new ArrayList<>()); 146 } 147 methods.add(mtype); 148 } 149 150 /** 151 * Lookup a primitive operator or function in the symbol table by 152 * prepending the prefix <tt>PrimopPrefix</tt>. 153 */ 154 public List<MethodType> lookupPrimop(String name) { 155 return _primops.get(name); 156 } 157 158 /** 159 * This is used for xsl:attribute elements that have a "namespace" 160 * attribute that is currently not defined using xmlns: 161 */ 162 private int _nsCounter = 0; 163 164 public String generateNamespacePrefix() { 165 return("ns"+(_nsCounter++)); 166 } 167 168 /** 169 * Use a namespace prefix to lookup a namespace URI 170 */ 171 private SyntaxTreeNode _current = null; 172 173 public void setCurrentNode(SyntaxTreeNode node) { 174 _current = node; 175 } 176 177 public String lookupNamespace(String prefix) { 178 if (_current == null) return(Constants.EMPTYSTRING); 179 return(_current.lookupNamespace(prefix)); 180 } 181 182 /** 183 * Adds an alias for a namespace prefix 184 */ 185 public void addPrefixAlias(String prefix, String alias) { 186 if (_aliases == null) _aliases = new HashMap<>(); 187 _aliases.put(prefix,alias); 188 } 189 190 /** 191 * Retrieves any alias for a given namespace prefix 192 */ 193 public String lookupPrefixAlias(String prefix) { 194 if (_aliases == null) return null; 195 return _aliases.get(prefix); 196 } 197 198 /** 199 * Register a namespace URI so that it will not be declared in the output 200 * unless it is actually referenced in the output. 201 */ 202 public void excludeURI(String uri) { 203 // The null-namespace cannot be excluded 204 if (uri == null) return; 205 206 // Create a new map of exlcuded URIs if none exists 207 if (_excludedURI == null) _excludedURI = new HashMap<>(); 208 209 // Register the namespace URI 210 Integer refcnt = _excludedURI.get(uri); 211 if (refcnt == null) 212 refcnt = 1; 213 else 214 refcnt = refcnt + 1; 215 _excludedURI.put(uri,refcnt); 216 } 217 218 /** 219 * Exclude a series of namespaces given by a list of whitespace 220 * separated namespace prefixes. 221 */ 222 public void excludeNamespaces(String prefixes) { 223 if (prefixes != null) { 224 StringTokenizer tokens = new StringTokenizer(prefixes); 225 while (tokens.hasMoreTokens()) { 226 final String prefix = tokens.nextToken(); 227 final String uri; 228 if (prefix.equals("#default")) 229 uri = lookupNamespace(Constants.EMPTYSTRING); 230 else 231 uri = lookupNamespace(prefix); 232 if (uri != null) excludeURI(uri); 233 } 234 } 235 } 236 237 /** 238 * Check if a namespace should not be declared in the output (unless used) 239 */ 240 public boolean isExcludedNamespace(String uri) { 241 if (uri != null && _excludedURI != null) { 242 final Integer refcnt = _excludedURI.get(uri); 243 return (refcnt != null && refcnt > 0); 244 } 245 return false; 246 } 247 248 /** 249 * Turn of namespace declaration exclusion 250 */ 251 public void unExcludeNamespaces(String prefixes) { 252 if (_excludedURI == null) return; 253 if (prefixes != null) { 254 StringTokenizer tokens = new StringTokenizer(prefixes); 255 while (tokens.hasMoreTokens()) { 256 final String prefix = tokens.nextToken(); 257 final String uri; 258 if (prefix.equals("#default")) 259 uri = lookupNamespace(Constants.EMPTYSTRING); 260 else 261 uri = lookupNamespace(prefix); 262 Integer refcnt = _excludedURI.get(uri); 263 if (refcnt != null) 264 _excludedURI.put(uri, refcnt - 1); 265 } 266 } 267 } 268 /** 269 * Exclusion of namespaces by a stylesheet does not extend to any stylesheet 270 * imported or included by the stylesheet. Upon entering the context of a 271 * new stylesheet, a call to this method is needed to clear the current set 272 * of excluded namespaces temporarily. Every call to this method requires 273 * a corresponding call to {@link #popExcludedNamespacesContext()}. 274 */ 275 public void pushExcludedNamespacesContext() { 276 if (_excludedURIStack == null) { 277 _excludedURIStack = new Stack<>(); 278 } 279 _excludedURIStack.push(_excludedURI); 280 _excludedURI = null; 281 } 282 283 /** 284 * Exclusion of namespaces by a stylesheet does not extend to any stylesheet 285 * imported or included by the stylesheet. Upon exiting the context of a 286 * stylesheet, a call to this method is needed to restore the set of 287 * excluded namespaces that was in effect prior to entering the context of 288 * the current stylesheet. 289 */ 290 public void popExcludedNamespacesContext() { 291 _excludedURI = _excludedURIStack.pop(); 292 if (_excludedURIStack.isEmpty()) { 293 _excludedURIStack = null; 294 } 295 } 296 297 }