tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/engine/rules/SourceParserRuleBase.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/engine/rules/SourceParserRuleBase.java Fri Oct 08 14:56:39 2010 +0300
@@ -0,0 +1,565 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+* Implementation of parser rule
+*
+*/
+package com.nokia.tracecompiler.engine.rules;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.nokia.tracecompiler.engine.TraceLocation;
+import com.nokia.tracecompiler.engine.TraceCompilerEngineErrorCodes.StringErrorParameters;
+import com.nokia.tracecompiler.engine.TraceCompilerEngineErrorCodes.TraceCompilerErrorCode;
+import com.nokia.tracecompiler.engine.source.SourceParserResult;
+import com.nokia.tracecompiler.engine.source.SourceParserRule;
+import com.nokia.tracecompiler.engine.utils.TraceUtils;
+import com.nokia.tracecompiler.model.Trace;
+import com.nokia.tracecompiler.model.TraceCompilerException;
+import com.nokia.tracecompiler.model.TraceModelExtension;
+import com.nokia.tracecompiler.project.TraceLocationParser;
+import com.nokia.tracecompiler.project.TraceProjectAPI;
+import com.nokia.tracecompiler.source.FormatMapping;
+import com.nokia.tracecompiler.source.SourceConstants;
+import com.nokia.tracecompiler.source.SourceExcludedArea;
+import com.nokia.tracecompiler.source.SourceIterator;
+import com.nokia.tracecompiler.source.SourceParser;
+import com.nokia.tracecompiler.source.SourceParserException;
+import com.nokia.tracecompiler.source.SourceUtils;
+
+/**
+ * Base class for parser rules. Instances of this class are added to the trace
+ * model. The source engine uses the parses it finds from the model to find
+ * trace locations from source files
+ *
+ */
+public abstract class SourceParserRuleBase extends RuleBase implements
+ SourceParserRule, TraceLocationParser {
+
+ /**
+ * Tag to be searched from source
+ */
+ private String tag;
+
+ /**
+ * Allowed tag suffixes
+ */
+ private ArrayList<String> tagSuffixes = new ArrayList<String>();
+
+ /**
+ * Default name for a parameter
+ */
+ public static final String DEFAULT_PARAMETER_NAME = "arg"; //$NON-NLS-1$
+
+ /**
+ * Pattern for trimming c++ cast operator away from trace parameters
+ */
+ private Pattern cppCastTrimPattern = Pattern.compile("\\s*(.+<.+>)\\s*"); //$NON-NLS-1$
+
+ /**
+ * Pattern for trimming c cast operator away from trace parameters
+ */
+ private Pattern cCastTrimPattern = Pattern.compile("(\\([^(]+?\\))"); //$NON-NLS-1$
+
+ /**
+ * Pattern for getting a valid token from parameter data
+ */
+ private Pattern parameterNamePattern = Pattern
+ .compile("[a-zA-Z][a-zA-Z\\d]*"); //$NON-NLS-1$
+
+ /**
+ * Symbian literal tags
+ */
+ private String[] TRACE_TEXT_TAGS = { "_L8", //$NON-NLS-1$
+ "_T8", //$NON-NLS-1$
+ "_L", //$NON-NLS-1$
+ "_T" //$NON-NLS-1$
+ };
+
+
+ /**
+ * Constructor
+ *
+ * @param tag
+ * the tag to be searched from source
+ * @param tagSuffixes
+ * the list of allowed suffixes to the tag
+ */
+ protected SourceParserRuleBase(String tag, String[] tagSuffixes) {
+ this.tag = tag;
+ // Adds the sub-formats to the parsers
+ if (tagSuffixes != null) {
+ int len = tagSuffixes.length;
+ for (int i = 0; i < len; i++) {
+ this.tagSuffixes.add(tagSuffixes[i]);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.engine.source.SourceParserRule#getSearchTag()
+ */
+ public String getSearchTag() {
+ return tag;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.engine.source.SourceParserRule#
+ * isAllowedTagSuffix(java.lang.String)
+ */
+ public boolean isAllowedTagSuffix(String tag) {
+ boolean retval = false;
+ if (tag != null) {
+ if (tag.length() == 0 && tagSuffixes.isEmpty()) {
+ retval = true;
+ } else {
+ for (int i = 0; i < tagSuffixes.size() && !retval; i++) {
+ String s = tagSuffixes.get(i);
+ if (s.length() == tag.length()) {
+ retval = true;
+ for (int j = 0; j < s.length() && retval; j++) {
+ char c1 = s.charAt(j);
+ // '?' can be any character
+ if (c1 != '?') {
+ retval = tag.charAt(j) == c1;
+ }
+ }
+ }
+ }
+ }
+ }
+ return retval;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.engine.source.SourceParserRule#getName()
+ */
+ public String getName() {
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.engine.source.SourceParserRule#
+ * parseParameters(java.util.List)
+ */
+ public SourceParserResult parseParameters(String tag, List<String> list)
+ throws TraceCompilerException {
+ SourceParserResult result = new SourceParserResult();
+ result.traceText = trimTraceText(list.get(0));
+ result.originalName = result.traceText;
+ result.convertedName = TraceUtils.convertName(
+ SourceUtils.removePrintfFormatting(result.traceText))
+ .toUpperCase();
+ result.parameters = list.subList(1, list.size());
+ return result;
+ }
+
+ /**
+ * Converts a location to trace
+ *
+ * @param location
+ * the location to be converted
+ * @return the conversion result
+ * @throws TraceCompilerException
+ * if conversion fails
+ */
+ public TraceConversionResult convertLocation(TraceLocation location)
+ throws TraceCompilerException {
+ // All parameter types are supported by default -> false is passed to
+ // buildParameterTypeList.
+ List<FormatMapping> types = buildParameterTypeList(location
+ .getTraceText(), false);
+ // Parameter count must match the number of format elements in trace
+ // text -> true is passed to convertLocation by default
+ return convertLocation(location, true, types);
+ }
+
+ /**
+ * Converts a location to trace
+ *
+ * @param location
+ * the location to be converted
+ * @param useParametersFromLocation
+ * true if location parameters need to be checked
+ * @param types
+ * the parameter types list
+ * @return the conversion result
+ * @throws TraceCompilerException
+ * if conversion fails
+ */
+ protected TraceConversionResult convertLocation(TraceLocation location,
+ boolean useParametersFromLocation, List<FormatMapping> types)
+ throws TraceCompilerException {
+ TraceConversionResult result = new TraceConversionResult();
+ result.text = location.getTraceText();
+
+ // If trace text is in multiple lines, remove extra characters
+ int removableAreaBeging = -1;
+ for (int i = 0; i < result.text.length(); i++) {
+ char c = result.text.charAt(i);
+ if (c == SourceConstants.QUOTE_CHAR
+ && (i == 0 || result.text.charAt(i - 1) != SourceConstants.BACKSLASH_CHAR)) {
+ if (removableAreaBeging != -1) {
+ String startString = result.text.substring(0,
+ removableAreaBeging);
+ String endString = result.text.substring(i + 1, result.text
+ .length());
+ result.text = startString + endString;
+ i = removableAreaBeging;
+ removableAreaBeging = -1;
+ } else {
+ removableAreaBeging = i;
+ }
+ }
+ }
+
+ result.name = location.getConvertedName();
+
+ // If location parameters are used, the count must match the number of
+ // formats parsed from the trace string.
+ if (!useParametersFromLocation
+ || (types.size() == location.getParameterCount() && numberOfParametersInTagMatchSize(
+ location.getTag(), types.size()))) {
+ result.parameters = new ArrayList<ParameterConversionResult>(types
+ .size());
+ Iterator<String> itr = location.getParameters();
+ // The FormatMapping objects are converted to
+ // ParameterConversionResult objects:
+ // - Name is associated to the parameter
+ // - Extensions are created
+ for (int i = 0; i < types.size(); i++) {
+ FormatMapping mapping = types.get(i);
+ String name;
+ if (useParametersFromLocation) {
+ name = TraceUtils.convertName(trimParameter(itr.next(), i));
+ } else {
+ name = DEFAULT_PARAMETER_NAME + (i + 1);
+ }
+ ParameterConversionResult param = mapFormatToConversionResult(mapping);
+ param.name = modifyDuplicateName(result.parameters, name);
+ result.parameters.add(param);
+ }
+ } else {
+ throw new TraceCompilerException(
+ TraceCompilerErrorCode.PARAMETER_FORMAT_MISMATCH, null,
+ location);
+ }
+ return result;
+ }
+
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.engine.source.SourceParserRule#
+ * processNewLocation(com.nokia.tracecompiler.engine.TraceLocation)
+ */
+ public void processNewLocation(TraceLocation location) {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.project.TraceLocationParser#getLocationGroup()
+ */
+ public String getLocationGroup() {
+ return null;
+ }
+
+ /**
+ * Maps a format to conversion result
+ *
+ * @param mapping
+ * the mapping
+ * @return the conversion result
+ */
+ protected ParameterConversionResult mapFormatToConversionResult(
+ FormatMapping mapping) {
+ ParameterConversionResult param = new ParameterConversionResult();
+ param.type = mapping.type;
+ if (mapping.isArray) {
+ param.extensions = new ArrayList<TraceModelExtension>();
+ param.extensions.add(new ArrayParameterRuleImpl());
+ }
+ return param;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.engine.source.SourceParserRule#
+ * findLocationComment(com.nokia.tracecompiler.engine.TraceLocation)
+ */
+ public SourceExcludedArea findLocationComment(TraceLocation location) {
+ SourceParser parser = location.getParser();
+ SourceExcludedArea excludedArea = null;
+ if (parser != null) {
+ try {
+ int offset = location.getOffset() + location.getLength();
+ SourceIterator itr = parser.createIterator(offset,
+ SourceParser.SKIP_WHITE_SPACES);
+ char c = itr.next();
+ if (c == ';') {
+ offset = itr.currentIndex();
+ c = itr.next();
+ }
+ boolean skippedReturn = false;
+ int commentStart = itr.currentIndex();
+ for (int i = offset; i < commentStart; i++) {
+ c = parser.getData(i);
+ if (c == '\n') {
+ skippedReturn = true;
+ }
+ }
+ // Comment must be on same line
+ if (!skippedReturn) {
+ excludedArea = parser.getExcludedArea(commentStart);
+ }
+ if (excludedArea == null) {
+ // If comment is not on same line, the previous line is
+ // checked
+ offset = parser.findStartOfLine(location.getOffset(), true,
+ true);
+ excludedArea = parser.getExcludedArea(offset - 1);
+ }
+ } catch (SourceParserException e) {
+ }
+ }
+ return excludedArea;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.engine.source.SourceParserRule#getLocationParser()
+ */
+ public TraceLocationParser getLocationParser() {
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.project.TraceLocationParser#
+ * isLocationConverted(com.nokia.tracecompiler.engine.TraceLocation)
+ */
+ public boolean isLocationConverted(TraceLocation location) {
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.nokia.tracecompiler.project.TraceLocationParser#
+ * checkLocationValidity(com.nokia.tracecompiler.engine.TraceLocation)
+ */
+ public TraceCompilerErrorCode checkLocationValidity(TraceLocation location) {
+ Trace trace = location.getTrace();
+ TraceCompilerErrorCode retval = TraceCompilerErrorCode.TRACE_DOES_NOT_EXIST;
+ if (trace != null) {
+ retval = TraceCompilerErrorCode.OK;
+ } else {
+ // If the API does not match the parser, the needs conversion flag
+ // is set
+ TraceProjectAPI api = getOwner().getModel().getExtension(
+ TraceProjectAPI.class);
+ if (!api.getName().equals(location.getParserRule().getName())) {
+ retval = TraceCompilerErrorCode.TRACE_NEEDS_CONVERSION;
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Checks if the number of the parameters in the trace tag matches the size
+ * of parameter list
+ *
+ * @param tag
+ * the trace tag
+ * @param size
+ * size of the parameter list
+ * @return true is parameter count matches, false otherwise
+ */
+ private boolean numberOfParametersInTagMatchSize(String tag, int size) {
+ boolean matches = true;
+ // Parse the last character of the tag to a integer
+ if (tag != null) {
+ try {
+
+ // Check the tag parameter count and compare it to the size of
+ // the parameter list
+ String tagParamStr = tag.substring(tag.length() - 1);
+ int tagParamCount = Integer.parseInt(tagParamStr);
+
+ if (tagParamCount != size) {
+ matches = false;
+ }
+ } catch (NumberFormatException e) {
+ }
+ }
+ return matches;
+ }
+
+ /**
+ * Builds the parameter type array which is passed to convertLocation
+ *
+ * @param text
+ * the trace text
+ * @param simpleParameters
+ * true if only simple types are supported
+ * @return the list of types
+ * @throws TraceCompilerException
+ * if parser fails
+ */
+ protected List<FormatMapping> buildParameterTypeList(String text,
+ boolean simpleParameters) throws TraceCompilerException {
+ Matcher matcher = SourceUtils.traceTextPattern.matcher(text);
+ ArrayList<FormatMapping> types = new ArrayList<FormatMapping>();
+ boolean found = true;
+ do {
+ found = matcher.find();
+ if (found) {
+ String tag = matcher.group();
+ FormatMapping mapping = SourceUtils
+ .mapFormatToParameterType(tag);
+ if (simpleParameters && !mapping.isSimple) {
+ StringErrorParameters param = new StringErrorParameters();
+ param.string = tag;
+ throw new TraceCompilerException(
+ TraceCompilerErrorCode.PARAMETER_FORMAT_NEEDS_EXT_MACRO,
+ param, null);
+ }
+ types.add(mapping);
+ }
+ } while (found);
+ return types;
+ }
+
+ /**
+ * Changes a duplicate parameter name to unique
+ *
+ * @param parameters
+ * the list of existing parameters
+ * @param name
+ * the name
+ * @return the modified name
+ */
+ private String modifyDuplicateName(
+ List<ParameterConversionResult> parameters, String name) {
+ String retval = name;
+ for (ParameterConversionResult result : parameters) {
+ if (result.name.equals(name)) {
+ retval = name + (parameters.size() + 1);
+ break;
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Trims extra stuff away from trace text
+ *
+ * @param data
+ * the data to be trimmed
+ * @return trimmed text
+ */
+ protected String trimTraceText(String data) {
+ // Removes literal macros
+ for (String element : TRACE_TEXT_TAGS) {
+ if (data.startsWith(element)) {
+ data = data.substring(element.length());
+ }
+ }
+ data = data.trim();
+ // Removes the opening bracket and quotes
+ data = removeBrackets(data);
+ if (data.startsWith("\"") //$NON-NLS-1$
+ && data.length() >= 2) { // CodForChk_Dis_Magic
+ data = data.substring(1, data.length() - 1);
+ }
+ return data;
+ }
+
+ /**
+ * Removes the brackets around the given data
+ *
+ * @param data
+ * the data
+ * @return the modified data
+ */
+ protected String removeBrackets(String data) {
+ boolean canRemove = true;
+ while (data.startsWith("(") //$NON-NLS-1$
+ && data.endsWith(")") //$NON-NLS-1$
+ && canRemove) {
+ // If closing bracket is found first, the first bracket cannot be
+ // removed.
+ // TODO: Does not work with for example ((Cast)abc).Func()
+ // -> (Cast)abc).Func(
+ for (int i = 1; i < data.length() - 1 && canRemove; i++) {
+ if (data.charAt(i) == '(') {
+ i = data.length();
+ } else if (data.charAt(i) == ')') {
+ canRemove = false;
+ }
+ }
+ if (canRemove) {
+ data = data.substring(1, data.length() - 1).trim();
+ }
+ }
+ return data;
+ }
+
+ /**
+ * Trims extra stuff away from a parameter to create a parameter label
+ *
+ * @param data
+ * the parameter data
+ * @param index
+ * the parameter index. The index will be used as label if the
+ * label cannot be parsed
+ * @return the parameter label
+ */
+ protected String trimParameter(String data, int index) {
+ // Removes possible literal macros
+ data = trimTraceText(data);
+ // Removes casting operations.
+ Matcher matcher = cppCastTrimPattern.matcher(data);
+ data = removeBrackets(matcher.replaceFirst("")); //$NON-NLS-1$
+ matcher = cCastTrimPattern.matcher(data);
+ data = matcher.replaceFirst(""); //$NON-NLS-1$
+ // Finds the next valid token from the data
+ matcher = parameterNamePattern.matcher(data);
+ if (matcher.find()) {
+ data = matcher.group();
+ } else {
+ data = DEFAULT_PARAMETER_NAME + (index + 1);
+ }
+ return data;
+ }
+}
\ No newline at end of file