/******************************************************************************* * Copyright (c) 2008, 2010 Borland Software 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 * * Contributors: * Borland Software Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.compiler; import java.util.Arrays; import lpg.runtime.IntSegmentedTuple; import org.eclipse.m2m.internal.qvt.oml.common.util.LineNumberProvider; import org.eclipse.ocl.lpg.AbstractLexer; /** * Implements quick search of a line number for a given position within a string */ class BasicLineNumberProvider implements LineNumberProvider { private int[] fLineEnds; BasicLineNumberProvider(int[] lineEnds) { fLineEnds = lineEnds.clone(); } BasicLineNumberProvider(AbstractLexer lexer) { IntSegmentedTuple lineOffsets = lexer.getILexStream().getLineOffsets(); int[] lines = new int[lineOffsets.size()]; boolean containsNegative = false; boolean isSorted = true; for (int i = 0; i < lines.length; i++) { lines[i] = lineOffsets.get(i); if(lines[i] < 0) { containsNegative = true; } if(i == lines.length - 1) { // last index, we must have been sorted break; } int next = lineOffsets.get(i + 1); if(lines[i] < next == false) { isSorted = false; break; } } if(!isSorted) { Arrays.sort(lines); } if(containsNegative) { int negativeCount = 0; for (int i = 0; i < lines.length; i++) { if(lines[i] < 0) { negativeCount++; } else { // we are sorted, can leave break; } } int[] newLines = new int[lines.length - negativeCount]; System.arraycopy(lines, negativeCount, newLines, 0, lines.length - negativeCount); lines = newLines; } fLineEnds = lines; } int[] lineBreakOffsets() { return fLineEnds.clone(); } public int getLineEnd(int lineNumber) { return getLineEndInt(lineNumber - 1); } public int getLineCount() { return fLineEnds.length; } public int getLineNumber(int offset) { if (offset < 0) { return -1; } return getLineNumberInt(offset) + 1; } /* Internal implementation: zero-based line numeration */ private int getLineEndInt(int lineNumber) { if(lineNumber >= 0 && lineNumber < fLineEnds.length) { return fLineEnds[lineNumber]; } return -1; } public int getLineNumberInt(int offset) { int index = searchLineForOffset(offset); return index < 0 ? -index : index == 0 ? 1 : index; } private int searchLineForOffset(int offset) { int low = 0; int high = fLineEnds.length; while (high > low) { int mid = (high + low) / 2, mid_element = fLineEnds[mid]; if (offset == mid_element) return mid; else if (offset < mid_element) high = mid; else low = mid + 1; } return -low; } }