tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/engine/rules/SourceParserRuleBase.java
changeset 56 aa2539c91954
equal deleted inserted replaced
54:a151135b0cf9 56:aa2539c91954
       
     1 /*
       
     2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 * Implementation of parser rule
       
    17 *
       
    18 */
       
    19 package com.nokia.tracecompiler.engine.rules;
       
    20 
       
    21 import java.util.ArrayList;
       
    22 import java.util.Iterator;
       
    23 import java.util.List;
       
    24 import java.util.regex.Matcher;
       
    25 import java.util.regex.Pattern;
       
    26 
       
    27 import com.nokia.tracecompiler.engine.TraceLocation;
       
    28 import com.nokia.tracecompiler.engine.TraceCompilerEngineErrorCodes.StringErrorParameters;
       
    29 import com.nokia.tracecompiler.engine.TraceCompilerEngineErrorCodes.TraceCompilerErrorCode;
       
    30 import com.nokia.tracecompiler.engine.source.SourceParserResult;
       
    31 import com.nokia.tracecompiler.engine.source.SourceParserRule;
       
    32 import com.nokia.tracecompiler.engine.utils.TraceUtils;
       
    33 import com.nokia.tracecompiler.model.Trace;
       
    34 import com.nokia.tracecompiler.model.TraceCompilerException;
       
    35 import com.nokia.tracecompiler.model.TraceModelExtension;
       
    36 import com.nokia.tracecompiler.project.TraceLocationParser;
       
    37 import com.nokia.tracecompiler.project.TraceProjectAPI;
       
    38 import com.nokia.tracecompiler.source.FormatMapping;
       
    39 import com.nokia.tracecompiler.source.SourceConstants;
       
    40 import com.nokia.tracecompiler.source.SourceExcludedArea;
       
    41 import com.nokia.tracecompiler.source.SourceIterator;
       
    42 import com.nokia.tracecompiler.source.SourceParser;
       
    43 import com.nokia.tracecompiler.source.SourceParserException;
       
    44 import com.nokia.tracecompiler.source.SourceUtils;
       
    45 
       
    46 /**
       
    47  * Base class for parser rules. Instances of this class are added to the trace
       
    48  * model. The source engine uses the parses it finds from the model to find
       
    49  * trace locations from source files
       
    50  * 
       
    51  */
       
    52 public abstract class SourceParserRuleBase extends RuleBase implements
       
    53 		SourceParserRule, TraceLocationParser {
       
    54 
       
    55 	/**
       
    56 	 * Tag to be searched from source
       
    57 	 */
       
    58 	private String tag;
       
    59 
       
    60 	/**
       
    61 	 * Allowed tag suffixes
       
    62 	 */
       
    63 	private ArrayList<String> tagSuffixes = new ArrayList<String>();
       
    64 
       
    65 	/**
       
    66 	 * Default name for a parameter
       
    67 	 */
       
    68 	public static final String DEFAULT_PARAMETER_NAME = "arg"; //$NON-NLS-1$
       
    69 
       
    70 	/**
       
    71 	 * Pattern for trimming c++ cast operator away from trace parameters
       
    72 	 */
       
    73 	private Pattern cppCastTrimPattern = Pattern.compile("\\s*(.+<.+>)\\s*"); //$NON-NLS-1$
       
    74 
       
    75 	/**
       
    76 	 * Pattern for trimming c cast operator away from trace parameters
       
    77 	 */
       
    78 	private Pattern cCastTrimPattern = Pattern.compile("(\\([^(]+?\\))"); //$NON-NLS-1$
       
    79 
       
    80 	/**
       
    81 	 * Pattern for getting a valid token from parameter data
       
    82 	 */
       
    83 	private Pattern parameterNamePattern = Pattern
       
    84 			.compile("[a-zA-Z][a-zA-Z\\d]*"); //$NON-NLS-1$
       
    85 
       
    86 	/**
       
    87 	 * Symbian literal tags
       
    88 	 */
       
    89 	private String[] TRACE_TEXT_TAGS = { "_L8", //$NON-NLS-1$
       
    90 			"_T8", //$NON-NLS-1$
       
    91 			"_L", //$NON-NLS-1$
       
    92 			"_T" //$NON-NLS-1$
       
    93 	};	
       
    94 	
       
    95 	
       
    96 	/**
       
    97 	 * Constructor
       
    98 	 * 
       
    99 	 * @param tag
       
   100 	 *            the tag to be searched from source
       
   101 	 * @param tagSuffixes
       
   102 	 *            the list of allowed suffixes to the tag
       
   103 	 */
       
   104 	protected SourceParserRuleBase(String tag, String[] tagSuffixes) {
       
   105 		this.tag = tag;
       
   106 		// Adds the sub-formats to the parsers
       
   107 		if (tagSuffixes != null) {
       
   108 			int len = tagSuffixes.length;
       
   109 			for (int i = 0; i < len; i++) {
       
   110 				this.tagSuffixes.add(tagSuffixes[i]);
       
   111 			}
       
   112 		}
       
   113 	}
       
   114 
       
   115 	/*
       
   116 	 * (non-Javadoc)
       
   117 	 * 
       
   118 	 * @see com.nokia.tracecompiler.engine.source.SourceParserRule#getSearchTag()
       
   119 	 */
       
   120 	public String getSearchTag() {
       
   121 		return tag;
       
   122 	}
       
   123 
       
   124 	/*
       
   125 	 * (non-Javadoc)
       
   126 	 * 
       
   127 	 * @see com.nokia.tracecompiler.engine.source.SourceParserRule#
       
   128 	 *      isAllowedTagSuffix(java.lang.String)
       
   129 	 */
       
   130 	public boolean isAllowedTagSuffix(String tag) {
       
   131 		boolean retval = false;
       
   132 		if (tag != null) {
       
   133 			if (tag.length() == 0 && tagSuffixes.isEmpty()) {
       
   134 				retval = true;
       
   135 			} else {
       
   136 				for (int i = 0; i < tagSuffixes.size() && !retval; i++) {
       
   137 					String s = tagSuffixes.get(i);
       
   138 					if (s.length() == tag.length()) {
       
   139 						retval = true;
       
   140 						for (int j = 0; j < s.length() && retval; j++) {
       
   141 							char c1 = s.charAt(j);
       
   142 							// '?' can be any character
       
   143 							if (c1 != '?') {
       
   144 								retval = tag.charAt(j) == c1;
       
   145 							}
       
   146 						}
       
   147 					}
       
   148 				}
       
   149 			}
       
   150 		}
       
   151 		return retval;
       
   152 	}
       
   153 
       
   154 	/*
       
   155 	 * (non-Javadoc)
       
   156 	 * 
       
   157 	 * @see com.nokia.tracecompiler.engine.source.SourceParserRule#getName()
       
   158 	 */
       
   159 	public String getName() {
       
   160 		return null;
       
   161 	}
       
   162 
       
   163 	/*
       
   164 	 * (non-Javadoc)
       
   165 	 * 
       
   166 	 * @see com.nokia.tracecompiler.engine.source.SourceParserRule#
       
   167 	 *      parseParameters(java.util.List)
       
   168 	 */
       
   169 	public SourceParserResult parseParameters(String tag, List<String> list)
       
   170 			throws TraceCompilerException {
       
   171 		SourceParserResult result = new SourceParserResult();
       
   172 		result.traceText = trimTraceText(list.get(0));
       
   173 		result.originalName = result.traceText;
       
   174 		result.convertedName = TraceUtils.convertName(
       
   175 				SourceUtils.removePrintfFormatting(result.traceText))
       
   176 				.toUpperCase();
       
   177 		result.parameters = list.subList(1, list.size());
       
   178 		return result;
       
   179 	}
       
   180 
       
   181 	/**
       
   182 	 * Converts a location to trace
       
   183 	 * 
       
   184 	 * @param location
       
   185 	 *            the location to be converted
       
   186 	 * @return the conversion result
       
   187 	 * @throws TraceCompilerException
       
   188 	 *             if conversion fails
       
   189 	 */
       
   190 	public TraceConversionResult convertLocation(TraceLocation location)
       
   191 			throws TraceCompilerException {
       
   192 		// All parameter types are supported by default -> false is passed to
       
   193 		// buildParameterTypeList.
       
   194 		List<FormatMapping> types = buildParameterTypeList(location
       
   195 				.getTraceText(), false);
       
   196 		// Parameter count must match the number of format elements in trace
       
   197 		// text -> true is passed to convertLocation by default
       
   198 		return convertLocation(location, true, types);
       
   199 	}
       
   200 	
       
   201 	/**
       
   202 	 * Converts a location to trace
       
   203 	 * 
       
   204 	 * @param location
       
   205 	 *            the location to be converted
       
   206 	 * @param useParametersFromLocation
       
   207 	 *            true if location parameters need to be checked
       
   208 	 * @param types
       
   209 	 *            the parameter types list
       
   210 	 * @return the conversion result
       
   211 	 * @throws TraceCompilerException
       
   212 	 *             if conversion fails
       
   213 	 */
       
   214 	protected TraceConversionResult convertLocation(TraceLocation location,
       
   215 			boolean useParametersFromLocation, List<FormatMapping> types)
       
   216 			throws TraceCompilerException {
       
   217 		TraceConversionResult result = new TraceConversionResult();
       
   218 		result.text = location.getTraceText();
       
   219 
       
   220 		// If trace text is in multiple lines, remove extra characters
       
   221 		int removableAreaBeging = -1;
       
   222 		for (int i = 0; i < result.text.length(); i++) {
       
   223 			char c = result.text.charAt(i);
       
   224 			if (c == SourceConstants.QUOTE_CHAR
       
   225 					&& (i == 0 || result.text.charAt(i - 1) != SourceConstants.BACKSLASH_CHAR)) {
       
   226 				if (removableAreaBeging != -1) {
       
   227 					String startString = result.text.substring(0,
       
   228 							removableAreaBeging);
       
   229 					String endString = result.text.substring(i + 1, result.text
       
   230 							.length());
       
   231 					result.text = startString + endString;
       
   232 					i = removableAreaBeging;
       
   233 					removableAreaBeging = -1;
       
   234 				} else {
       
   235 					removableAreaBeging = i;
       
   236 				}
       
   237 			}
       
   238 		}
       
   239 
       
   240 		result.name = location.getConvertedName();
       
   241 
       
   242 		// If location parameters are used, the count must match the number of
       
   243 		// formats parsed from the trace string.
       
   244 		if (!useParametersFromLocation
       
   245 				|| (types.size() == location.getParameterCount() && numberOfParametersInTagMatchSize(
       
   246 						location.getTag(), types.size()))) {
       
   247 			result.parameters = new ArrayList<ParameterConversionResult>(types
       
   248 					.size());
       
   249 			Iterator<String> itr = location.getParameters();
       
   250 			// The FormatMapping objects are converted to
       
   251 			// ParameterConversionResult objects:
       
   252 			// - Name is associated to the parameter
       
   253 			// - Extensions are created
       
   254 			for (int i = 0; i < types.size(); i++) {
       
   255 				FormatMapping mapping = types.get(i);
       
   256 				String name;
       
   257 				if (useParametersFromLocation) {
       
   258 					name = TraceUtils.convertName(trimParameter(itr.next(), i));
       
   259 				} else {
       
   260 					name = DEFAULT_PARAMETER_NAME + (i + 1);
       
   261 				}
       
   262 				ParameterConversionResult param = mapFormatToConversionResult(mapping);
       
   263 				param.name = modifyDuplicateName(result.parameters, name);
       
   264 				result.parameters.add(param);
       
   265 			}
       
   266 		} else {
       
   267 			throw new TraceCompilerException(
       
   268 					TraceCompilerErrorCode.PARAMETER_FORMAT_MISMATCH, null,
       
   269 					location);
       
   270 		}
       
   271 		return result;
       
   272 	}
       
   273 
       
   274 	
       
   275 	
       
   276 	/*
       
   277 	 * (non-Javadoc)
       
   278 	 * 
       
   279 	 * @see com.nokia.tracecompiler.engine.source.SourceParserRule#
       
   280 	 *      processNewLocation(com.nokia.tracecompiler.engine.TraceLocation)
       
   281 	 */
       
   282 	public void processNewLocation(TraceLocation location) {
       
   283 	}
       
   284 
       
   285 	/*
       
   286 	 * (non-Javadoc)
       
   287 	 * 
       
   288 	 * @see com.nokia.tracecompiler.project.TraceLocationParser#getLocationGroup()
       
   289 	 */
       
   290 	public String getLocationGroup() {
       
   291 		return null;
       
   292 	}
       
   293 
       
   294 	/**
       
   295 	 * Maps a format to conversion result
       
   296 	 * 
       
   297 	 * @param mapping
       
   298 	 *            the mapping
       
   299 	 * @return the conversion result
       
   300 	 */
       
   301 	protected ParameterConversionResult mapFormatToConversionResult(
       
   302 			FormatMapping mapping) {
       
   303 		ParameterConversionResult param = new ParameterConversionResult();
       
   304 		param.type = mapping.type;
       
   305 		if (mapping.isArray) {
       
   306 			param.extensions = new ArrayList<TraceModelExtension>();
       
   307 			param.extensions.add(new ArrayParameterRuleImpl());
       
   308 		}
       
   309 		return param;
       
   310 	}
       
   311 
       
   312 	/*
       
   313 	 * (non-Javadoc)
       
   314 	 * 
       
   315 	 * @see com.nokia.tracecompiler.engine.source.SourceParserRule#
       
   316 	 *      findLocationComment(com.nokia.tracecompiler.engine.TraceLocation)
       
   317 	 */
       
   318 	public SourceExcludedArea findLocationComment(TraceLocation location) {
       
   319 		SourceParser parser = location.getParser();
       
   320 		SourceExcludedArea excludedArea = null;
       
   321 		if (parser != null) {
       
   322 			try {
       
   323 				int offset = location.getOffset() + location.getLength();
       
   324 				SourceIterator itr = parser.createIterator(offset,
       
   325 						SourceParser.SKIP_WHITE_SPACES);
       
   326 				char c = itr.next();
       
   327 				if (c == ';') {
       
   328 					offset = itr.currentIndex();
       
   329 					c = itr.next();
       
   330 				}
       
   331 				boolean skippedReturn = false;
       
   332 				int commentStart = itr.currentIndex();
       
   333 				for (int i = offset; i < commentStart; i++) {
       
   334 					c = parser.getData(i);
       
   335 					if (c == '\n') {
       
   336 						skippedReturn = true;
       
   337 					}
       
   338 				}
       
   339 				// Comment must be on same line
       
   340 				if (!skippedReturn) {
       
   341 					excludedArea = parser.getExcludedArea(commentStart);
       
   342 				}
       
   343 				if (excludedArea == null) {
       
   344 					// If comment is not on same line, the previous line is
       
   345 					// checked
       
   346 					offset = parser.findStartOfLine(location.getOffset(), true,
       
   347 							true);
       
   348 					excludedArea = parser.getExcludedArea(offset - 1);
       
   349 				}
       
   350 			} catch (SourceParserException e) {
       
   351 			}
       
   352 		}
       
   353 		return excludedArea;
       
   354 	}
       
   355 
       
   356 	/*
       
   357 	 * (non-Javadoc)
       
   358 	 * 
       
   359 	 * @see com.nokia.tracecompiler.engine.source.SourceParserRule#getLocationParser()
       
   360 	 */
       
   361 	public TraceLocationParser getLocationParser() {
       
   362 		return this;
       
   363 	}
       
   364 
       
   365 	/*
       
   366 	 * (non-Javadoc)
       
   367 	 * 
       
   368 	 * @see com.nokia.tracecompiler.project.TraceLocationParser#
       
   369 	 *      isLocationConverted(com.nokia.tracecompiler.engine.TraceLocation)
       
   370 	 */
       
   371 	public boolean isLocationConverted(TraceLocation location) {
       
   372 		return false;
       
   373 	}
       
   374 
       
   375 	/*
       
   376 	 * (non-Javadoc)
       
   377 	 * 
       
   378 	 * @see com.nokia.tracecompiler.project.TraceLocationParser#
       
   379 	 *      checkLocationValidity(com.nokia.tracecompiler.engine.TraceLocation)
       
   380 	 */
       
   381 	public TraceCompilerErrorCode checkLocationValidity(TraceLocation location) {
       
   382 		Trace trace = location.getTrace();
       
   383 		TraceCompilerErrorCode retval = TraceCompilerErrorCode.TRACE_DOES_NOT_EXIST;
       
   384 		if (trace != null) {
       
   385 			retval = TraceCompilerErrorCode.OK;
       
   386 		} else {
       
   387 			// If the API does not match the parser, the needs conversion flag
       
   388 			// is set
       
   389 			TraceProjectAPI api = getOwner().getModel().getExtension(
       
   390 					TraceProjectAPI.class);
       
   391 			if (!api.getName().equals(location.getParserRule().getName())) {
       
   392 				retval = TraceCompilerErrorCode.TRACE_NEEDS_CONVERSION;
       
   393 			}
       
   394 		}
       
   395 		return retval;
       
   396 	}
       
   397 
       
   398 	/**
       
   399 	 * Checks if the number of the parameters in the trace tag matches the size
       
   400 	 * of parameter list
       
   401 	 * 
       
   402 	 * @param tag
       
   403 	 *            the trace tag
       
   404 	 * @param size
       
   405 	 *            size of the parameter list
       
   406 	 * @return true is parameter count matches, false otherwise
       
   407 	 */
       
   408 	private boolean numberOfParametersInTagMatchSize(String tag, int size) {
       
   409 		boolean matches = true;
       
   410 		// Parse the last character of the tag to a integer
       
   411 		if (tag != null) {
       
   412 			try {
       
   413 
       
   414 				// Check the tag parameter count and compare it to the size of
       
   415 				// the parameter list
       
   416 				String tagParamStr = tag.substring(tag.length() - 1);
       
   417 				int tagParamCount = Integer.parseInt(tagParamStr);
       
   418 
       
   419 				if (tagParamCount != size) {
       
   420 					matches = false;
       
   421 				}
       
   422 			} catch (NumberFormatException e) {
       
   423 			}
       
   424 		}
       
   425 		return matches;
       
   426 	}
       
   427 
       
   428 	/**
       
   429 	 * Builds the parameter type array which is passed to convertLocation
       
   430 	 * 
       
   431 	 * @param text
       
   432 	 *            the trace text
       
   433 	 * @param simpleParameters
       
   434 	 *            true if only simple types are supported
       
   435 	 * @return the list of types
       
   436 	 * @throws TraceCompilerException
       
   437 	 *             if parser fails
       
   438 	 */
       
   439 	protected List<FormatMapping> buildParameterTypeList(String text,
       
   440 			boolean simpleParameters) throws TraceCompilerException {
       
   441 		Matcher matcher = SourceUtils.traceTextPattern.matcher(text);
       
   442 		ArrayList<FormatMapping> types = new ArrayList<FormatMapping>();
       
   443 		boolean found = true;
       
   444 		do {
       
   445 			found = matcher.find();
       
   446 			if (found) {
       
   447 				String tag = matcher.group();
       
   448 				FormatMapping mapping = SourceUtils
       
   449 						.mapFormatToParameterType(tag);
       
   450 				if (simpleParameters && !mapping.isSimple) {
       
   451 					StringErrorParameters param = new StringErrorParameters();
       
   452 					param.string = tag;
       
   453 					throw new TraceCompilerException(
       
   454 							TraceCompilerErrorCode.PARAMETER_FORMAT_NEEDS_EXT_MACRO,
       
   455 							param, null);
       
   456 				}
       
   457 				types.add(mapping);
       
   458 			}
       
   459 		} while (found);
       
   460 		return types;
       
   461 	}
       
   462 
       
   463 	/**
       
   464 	 * Changes a duplicate parameter name to unique
       
   465 	 * 
       
   466 	 * @param parameters
       
   467 	 *            the list of existing parameters
       
   468 	 * @param name
       
   469 	 *            the name
       
   470 	 * @return the modified name
       
   471 	 */
       
   472 	private String modifyDuplicateName(
       
   473 			List<ParameterConversionResult> parameters, String name) {
       
   474 		String retval = name;
       
   475 		for (ParameterConversionResult result : parameters) {
       
   476 			if (result.name.equals(name)) {
       
   477 				retval = name + (parameters.size() + 1);
       
   478 				break;
       
   479 			}
       
   480 		}
       
   481 		return retval;
       
   482 	}
       
   483 
       
   484 	/**
       
   485 	 * Trims extra stuff away from trace text
       
   486 	 * 
       
   487 	 * @param data
       
   488 	 *            the data to be trimmed
       
   489 	 * @return trimmed text
       
   490 	 */
       
   491 	protected String trimTraceText(String data) {
       
   492 		// Removes literal macros
       
   493 		for (String element : TRACE_TEXT_TAGS) {
       
   494 			if (data.startsWith(element)) {
       
   495 				data = data.substring(element.length());
       
   496 			}
       
   497 		}
       
   498 		data = data.trim();
       
   499 		// Removes the opening bracket and quotes
       
   500 		data = removeBrackets(data);
       
   501 		if (data.startsWith("\"") //$NON-NLS-1$
       
   502 				&& data.length() >= 2) { // CodForChk_Dis_Magic
       
   503 			data = data.substring(1, data.length() - 1);
       
   504 		}
       
   505 		return data;
       
   506 	}
       
   507 
       
   508 	/**
       
   509 	 * Removes the brackets around the given data
       
   510 	 * 
       
   511 	 * @param data
       
   512 	 *            the data
       
   513 	 * @return the modified data
       
   514 	 */
       
   515 	protected String removeBrackets(String data) {
       
   516 		boolean canRemove = true;
       
   517 		while (data.startsWith("(") //$NON-NLS-1$
       
   518 				&& data.endsWith(")") //$NON-NLS-1$
       
   519 				&& canRemove) {
       
   520 			// If closing bracket is found first, the first bracket cannot be
       
   521 			// removed.
       
   522 			// TODO: Does not work with for example ((Cast)abc).Func()
       
   523 			// -> (Cast)abc).Func(
       
   524 			for (int i = 1; i < data.length() - 1 && canRemove; i++) {
       
   525 				if (data.charAt(i) == '(') {
       
   526 					i = data.length();
       
   527 				} else if (data.charAt(i) == ')') {
       
   528 					canRemove = false;
       
   529 				}
       
   530 			}
       
   531 			if (canRemove) {
       
   532 				data = data.substring(1, data.length() - 1).trim();
       
   533 			}
       
   534 		}
       
   535 		return data;
       
   536 	}
       
   537 
       
   538 	/**
       
   539 	 * Trims extra stuff away from a parameter to create a parameter label
       
   540 	 * 
       
   541 	 * @param data
       
   542 	 *            the parameter data
       
   543 	 * @param index
       
   544 	 *            the parameter index. The index will be used as label if the
       
   545 	 *            label cannot be parsed
       
   546 	 * @return the parameter label
       
   547 	 */
       
   548 	protected String trimParameter(String data, int index) {
       
   549 		// Removes possible literal macros
       
   550 		data = trimTraceText(data);
       
   551 		// Removes casting operations.
       
   552 		Matcher matcher = cppCastTrimPattern.matcher(data);
       
   553 		data = removeBrackets(matcher.replaceFirst("")); //$NON-NLS-1$
       
   554 		matcher = cCastTrimPattern.matcher(data);
       
   555 		data = matcher.replaceFirst(""); //$NON-NLS-1$
       
   556 		// Finds the next valid token from the data
       
   557 		matcher = parameterNamePattern.matcher(data);
       
   558 		if (matcher.find()) {
       
   559 			data = matcher.group();
       
   560 		} else {
       
   561 			data = DEFAULT_PARAMETER_NAME + (index + 1);
       
   562 		}
       
   563 		return data;
       
   564 	}	
       
   565 }