| /******************************************************************************* |
| * Copyright (c) 2008, 2018 Open Canarias S.L. and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * Adolfo Sanchez-Barbudo Herrera (Open Canarias)- Initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ocl.lpg; |
| |
| import java.util.ArrayList; |
| |
| import lpg.runtime.ErrorToken; |
| import lpg.runtime.ILexStream; |
| import lpg.runtime.IToken; |
| import lpg.runtime.ParseErrorCodes; |
| import lpg.runtime.PrsStream; |
| |
| |
| /** |
| * This DerivedLexStream will be used in favour of the LpgLexStream for the |
| * OCLLexer, so that some customization are introduced and exploited by the |
| * generated OCLLexer. |
| * |
| * @since 3.0 |
| */ |
| public class DerivedPrsStream extends PrsStream { |
| |
| private BasicEnvironment environment; |
| |
| public DerivedPrsStream(BasicEnvironment env, ILexStream iLexStream) { |
| super(iLexStream); |
| this.environment = env; |
| } |
| |
| /** |
| * This function returns the index of the token element containing the |
| * offset specified. If such a token does not exist, it returns the negation |
| * of the index of the element immediately preceding the offset. |
| * |
| * @since 1.3 |
| */ |
| public ErrorToken getErrorTokenAtCharacter(int offset) { |
| ErrorToken bestToken = null; |
| for (int i = getSize(); --i >= 0;) { |
| IToken token = getTokenAt(i); |
| if (!(token instanceof ErrorToken)) { |
| break; |
| } |
| IToken errorToken = ((ErrorToken) token).getErrorToken(); |
| if (offset >= errorToken.getStartOffset() |
| && offset <= errorToken.getEndOffset()) { |
| if ((bestToken == null) |
| || ((bestToken.getStartOffset() <= errorToken |
| .getStartOffset()) && (token.getEndOffset() <= errorToken |
| .getEndOffset()))) { |
| bestToken = (ErrorToken) token; |
| } |
| } |
| } |
| return bestToken; |
| } |
| |
| /** |
| * @since 1.3 |
| */ |
| public int getErrorTokens() { |
| return getTokens().size() - getStreamLength(); |
| } |
| |
| /** |
| * Overridden to search only the non-Error nodes, which are the only tokens |
| * in monotonic order. |
| */ |
| @Override |
| public int getTokenIndexAtCharacter(int offset) { |
| int low = 0; |
| int high = getSize(); |
| while (high > low) { |
| IToken highToken = getTokenAt(high - 1); |
| if (!(highToken instanceof ErrorToken)) { |
| break; |
| } |
| high--; |
| } |
| while (high > low) { |
| int mid = (high + low) / 2; |
| IToken mid_element = getTokenAt(mid); |
| if (offset >= mid_element.getStartOffset() |
| && offset <= mid_element.getEndOffset()) { |
| return mid; |
| } else if (offset < mid_element.getStartOffset()) { |
| high = mid; |
| } else { |
| low = mid + 1; |
| } |
| } |
| |
| return -(low - 1); |
| } |
| |
| @Override |
| public int makeErrorToken(int firsttok, int lasttok, int errortok, int kind) { |
| @SuppressWarnings("unchecked") |
| ArrayList<IToken> tokens = getTokens(); |
| int index = tokens.size(); // the next index |
| |
| // |
| // Note that when creating an error token, we do not remap its kind. |
| // Since this is not a lexical operation, it is the responsibility of |
| // the calling program (a parser driver) to pass to us the proper kind |
| // that it wants for an error token. |
| // |
| IToken token = new ErrorToken(getIToken(firsttok), getIToken(lasttok), |
| getIToken(errortok), getStartOffset(firsttok), |
| getEndOffset(lasttok), kind) { |
| |
| @Override |
| public String toString() { |
| if (getIPrsStream() == null) { |
| return "<toString>"; //$NON-NLS-1$ |
| } |
| int startOffset = getStartOffset(); |
| int length = getEndOffset() + 1 - startOffset; |
| if (length < 0) { |
| length = -length - 1; |
| startOffset = getEndOffset(); |
| } |
| if ((startOffset + length) > getIPrsStream().getInputChars().length) { |
| return String.valueOf(IToken.EOF); |
| } |
| return new String(getIPrsStream().getInputChars(), startOffset, |
| length); |
| } |
| |
| }; |
| token.setTokenIndex(index); |
| tokens.add(token); |
| token.setAdjunctIndex(getAdjuncts().size()); |
| return index; |
| } |
| |
| /** |
| * |
| * @since 3.0 |
| */ |
| @Override |
| public void reportError(int errorCode, int leftToken, int errorToken, |
| int rightToken, String[] errorInfo) { |
| |
| if (environment == null) { |
| super.reportError(errorCode, leftToken, errorToken, rightToken, errorInfo); |
| } else { |
| // TODO Revise this. BasicEnvironment.parserError doesn't have a String[] argument |
| String tokenText = errorInfo.length > 0 ? errorInfo[0] : ""; //$NON-NLS-1$ |
| if (errorCode == PrsStream.DELETION_CODE || errorCode == PrsStream.MISPLACED_CODE) { |
| tokenText = ""; //$NON-NLS-1$ |
| } |
| environment.parserError(errorCode, leftToken, rightToken, tokenText); |
| } |
| } |
| |
| /** |
| * Report error message for given error_token. |
| * |
| * @param error_token |
| * the error taken index |
| * @param msg |
| * the message to report |
| * |
| * @since 1.3 |
| */ |
| public final void reportErrorTokenMessage(int error_token, String msg) { |
| int firsttok = super.getFirstRealToken(error_token); |
| int lasttok = super.getLastRealToken(error_token); |
| if (firsttok > lasttok) { |
| reportError(ParseErrorCodes.INSERTION_CODE, lasttok, |
| lasttok, msg); |
| } else { |
| reportError(ParseErrorCodes.SUBSTITUTION_CODE, firsttok, |
| lasttok, msg); |
| } |
| } |
| } |