All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.ocl.parser.OCLAnalyzer Maven / Gradle / Ivy

/**
 * 
 *
 * Copyright (c) 2005, 2009 IBM Corporation, Zeligsoft Inc., 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: 
 *   IBM - Initial API and implementation
 *   E.D.Willink - refactored to separate from OCLAnalyzer and OCLParser
 *       - Bug 259818
 *   Zeligsoft - Bug 243976, 251349
 *
 * 
 *
 * $Id: OCLAnalyzer.java,v 1.11 2010/12/15 17:33:43 ewillink Exp $
 */

package org.eclipse.ocl.parser;

import java.util.List;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.cst.CSTNode;
import org.eclipse.ocl.cst.InitOrDerValueCS;
import org.eclipse.ocl.cst.InvCS;
import org.eclipse.ocl.cst.InvOrDefCS;
import org.eclipse.ocl.cst.OCLDocumentCS;
import org.eclipse.ocl.cst.OCLExpressionCS;
import org.eclipse.ocl.cst.PackageDeclarationCS;
import org.eclipse.ocl.cst.PrePostOrBodyDeclCS;
import org.eclipse.ocl.cst.PrePostOrBodyEnum;
import org.eclipse.ocl.cst.VariableCS;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.Variable;
import org.eclipse.ocl.helper.ConstraintKind;
import org.eclipse.ocl.internal.l10n.OCLMessages;
import org.eclipse.ocl.utilities.ExpressionInOCL;
import org.eclipse.ocl.utilities.OCLFactory;
import org.eclipse.ocl.utilities.TypedElement;

/**
 * The OCLAnalyzer performs semantic analysis on a CST produced by
 * an OCLParser to create the OCL AST. It is necessary that
 * syntactic parsing and semantic analysis are performed in two steps because
 * LPG is a bottom up parser and cannot provide enough contextual information to
 * create the AST on the first pass.
 */
public class OCLAnalyzer
		extends
		AbstractOCLAnalyzer {

	private OCLFactoryWithHistory history;

	/**
	 * Construct an OCL semantic analyzer that will use a given parser to
	 * perform syntactic and lexical analysis.
	 * 
	 * @param parser
	 *            the syntactic (and lexical) parser
	 * 
	 * @since 1.3
	 */
	public OCLAnalyzer(AbstractOCLParser parser) {
		super(parser);
	}

	/**
	 * Construct an OCL semantic analyzer that will use a given parser to
	 * perform syntactic and lexical analysis.
	 * 
	 * @param parser
	 *            the syntactic (and lexical) parser
	 */
	public OCLAnalyzer(OCLParser parser) {
		super(parser);
	}

	/**
	 * Construct an OCL semantic analyzer with default syntactic and lexical
	 * parsers all operating within a given environment.
	 * 
	 * @param environment
	 *            the symbolic and problem handling environment
	 */
	public OCLAnalyzer(
			Environment environment) {
		this(new OCLParser(new OCLLexer(environment)));
	}

	/**
	 * Construct an OCL semantic analyzer with default syntactic and lexical
	 * parsers all operating within a given environment. Then prime the analyzer
	 * by performing keyword and lexical parsing of the given source text.
	 * 
	 * @param environment
	 *            the symbolic and problem handling environment
	 * @param text
	 *            the source text for analysis
	 */
	public OCLAnalyzer(
			Environment environment,
			String text) {
		this(new OCLParser(new OCLLexer(environment, text.toCharArray())));
		getLexer().lexer(getAbstractParser().getIPrsStream());
	}

	/**
	 * @deprecated Use the {@link #getAbstractParser()} method, instead
	 */
	@Deprecated
	@Override
	public OCLParser getParser() {
		return (OCLParser) super.getParser();
	}

	@Override
	protected OCLFactory createOCLFactory(
			Environment env) {

		history = env.getFactory().createOCLFactoryWithHistory(env);
		return history;
	}

	private  T sanitize(T parseResult) {
		history.clear();
		return parseResult;
	}

	/**
	 * Performs a concrete-syntax parser and throws ParserException
	 * if any parse errors are encountered.
	 * 
	 * @return the parsed CST, or null if it could not be parsed
	 */
	public CSTNode parseConcreteSyntax() {
		return getAbstractParser().parser();
	}

	/**
	 * Parses the specified concrete syntax model to an abstract syntax model.
	 * The result is contained by an Constraint, so care must be taken
	 * when the result is no longer needed to dispose of the entire tree rooted
	 * in the Constraint.
	 * 
	 * @param cst
	 *            the OCL concrete syntax model
	 * @param constraintType
	 *            the kind of constraint to parse
	 * 
	 * @return the OCL expression, if it successfully parsed
	 */
	public OCLExpression parseAST(OCLExpressionCS cst,
			ConstraintKind constraintType) {
		AbstractOCLParser parser = getAbstractParser();
		OCLExpression result = null;
		switch (constraintType) {
			case PRECONDITION :
				PrePostOrBodyDeclCS pre = parser.createPrePostOrBodyDeclCS(
					PrePostOrBodyEnum.PRE_LITERAL, null, cst);
				result = uml.getSpecification(
					prePostOrBodyDeclCS(getOCLEnvironment(), pre))
					.getBodyExpression();
				break;
			case BODYCONDITION :
				PrePostOrBodyDeclCS body = parser.createPrePostOrBodyDeclCS(
					PrePostOrBodyEnum.BODY_LITERAL, null, cst);
				result = uml.getSpecification(
					prePostOrBodyDeclCS(getOCLEnvironment(), body))
					.getBodyExpression();
				break;
			case POSTCONDITION :
				PrePostOrBodyDeclCS post = parser.createPrePostOrBodyDeclCS(
					PrePostOrBodyEnum.POST_LITERAL, null, cst);
				result = uml.getSpecification(
					prePostOrBodyDeclCS(getOCLEnvironment(), post))
					.getBodyExpression();
				break;
			default :
				InvCS inv = parser.createInvCS(null, cst);
				result = uml.getSpecification(invCS(inv, getOCLEnvironment()))
					.getBodyExpression();
				break;
		}

		return sanitize(result);
	}

	/**
	 * Parses the input as an OCLDocumentCS.
	 * 
	 * @param constraints
	 *            the constraints list to populate
	 * @return the parsed constraints (as many as could be parsed)
	 * 
	 * @since 1.3
	 */
	public List parseOCLDocument(final List constraints) {
		CSTNode cstNode = parseConcreteSyntax();

		if ((cstNode != null) && !(cstNode instanceof PackageDeclarationCS)) {
			ERROR(cstNode, "parseOCLDocument",//$NON-NLS-1$
				OCLMessages.bind(OCLMessages.ParseCSTNodeType_ERROR_,
					"PackageDeclarationCS",//$NON-NLS-1$
					cstNode.eClass().getName()));
			return sanitize(constraints);
		}

		OCLDocumentCS documentCS = getAbstractParser().createOCLDocumentCS(
			(PackageDeclarationCS) cstNode);

		documentCS(documentCS, constraints);

		return sanitize(constraints);
	}

	/**
	 * Parses the input as a PackageDeclarationCS.
	 * 
	 * @param constraints
	 * @return the parsed constraints (as many as could be parsed)
	 */
	public List parsePackageDeclarationCS(List constraints) {
		CSTNode cstNode = parseConcreteSyntax();

		if ((cstNode != null) && !(cstNode instanceof PackageDeclarationCS)) {
			ERROR(cstNode, "parsePackageDeclarationCS",//$NON-NLS-1$
				OCLMessages.bind(OCLMessages.ParseCSTNodeType_ERROR_,
					"PackageDeclarationCS",//$NON-NLS-1$
					cstNode.eClass().getName()));
			return sanitize(constraints);
		}

		List packageDecls = new BasicEList.FastCompare(
			4);

		// reverse the chain of package declarations to process them in the
		// forward order
		PackageDeclarationCS pkgdecl = (PackageDeclarationCS) cstNode;
		while (pkgdecl != null) {
			packageDecls.add(0, pkgdecl);
			pkgdecl = pkgdecl.getPackageDeclarationCS();
		}

		for (PackageDeclarationCS packageDeclCS : packageDecls) {
			packageDeclarationCS(packageDeclCS, constraints);
		}

		return sanitize(constraints);
	}

	/**
	 * Parses the input as an InvOrDefCS.
	 * 
	 * @return the parsed OCL constraint, or null if it could not
	 *         be parsed
	 */
	public CT parseInvOrDefCS() {

		CSTNode cstNode = parseConcreteSyntax();
		if (cstNode != null) {
			if (cstNode instanceof InvOrDefCS) {
				return sanitize(invOrDefCS((InvOrDefCS) cstNode,
					getOCLEnvironment()));
			}

			ERROR(cstNode, "parseInvOrDefCS",//$NON-NLS-1$
				OCLMessages.bind(OCLMessages.ParseCSTNodeType_ERROR_,
					"InvOrDefCS",//$NON-NLS-1$
					cstNode.eClass().getName()));
		}

		return sanitize(null);
	}

	/**
	 * Parses the input as a PrePostOrBodyDeclCS.
	 * 
	 * @return the parsed OCL constraint, or null if it could not
	 *         be parsed
	 */
	public CT parsePrePostOrBodyDeclCS() {

		CSTNode cstNode = parseConcreteSyntax();
		if (cstNode != null) {
			if (cstNode instanceof PrePostOrBodyDeclCS) {
				return sanitize(prePostOrBodyDeclCS(getOCLEnvironment(),
					(PrePostOrBodyDeclCS) cstNode));
			}
		}

		ERROR(cstNode, "parsePrePostOrBodyDeclCS",//$NON-NLS-1$
			OCLMessages.bind(OCLMessages.ParseCSTNodeType_ERROR_,
				"PrePostOrBodyDeclCS",//$NON-NLS-1$
				formatEClassName(cstNode)));
		return sanitize(null);
	}

	/**
	 * Parses the input as an InitOrDerValueCS.
	 * 
	 * @return the parsed OCL constraint, or null if it could not
	 *         be parsed
	 */
	public CT parseInitOrDerValueCS() {

		CSTNode cstNode = parseConcreteSyntax();
		if (cstNode != null) {
			if (cstNode instanceof InitOrDerValueCS) {
				return sanitize(initOrDerValueCS(getOCLEnvironment(),
					(InitOrDerValueCS) cstNode));
			}
		}

		ERROR(cstNode, "parseInitOrDerValueCS",//$NON-NLS-1$
			OCLMessages.bind(OCLMessages.ParseCSTNodeType_ERROR_,
				"InitOrDerValueCS",//$NON-NLS-1$
				formatEClassName(cstNode)));
		return sanitize(null);
	}

	/**
	 * Parses the input as a VariableDeclarationCS.
	 * 
	 * @param addToEnvironment
	 *            boolean whether or not to add the the parsed variable to the
	 *            environment
	 * @return the parsed variable declaration, or null if it could
	 *         not be parsed
	 */
	public Variable parseVariableDeclarationCS(boolean addToEnvironment) {

		CSTNode cstNode = parseConcreteSyntax();
		if (cstNode != null) {
			if (cstNode instanceof VariableCS) {
				return sanitize(variableDeclarationCS((VariableCS) cstNode,
					getOCLEnvironment(), true));
			}

			ERROR(cstNode, "parseVariableDeclarationCS",//$NON-NLS-1$
				OCLMessages.bind(OCLMessages.ParseCSTNodeType_ERROR_,
					"VariableDeclarationCS",//$NON-NLS-1$
					cstNode.eClass().getName()));
		}
		return sanitize(null);
	}

	@Override
	public void ERROR(List problemObjects, String rule, String problemMessage) {
		history.setDisposable();
		super.ERROR(problemObjects, rule, problemMessage);
	}

	@Override
	public void ERROR(Object problemObject, String rule, String problemMessage) {
		history.setDisposable();
		super.ERROR(problemObject, rule, problemMessage);
	}

	@Override
	public void ERROR(String problemMessage) {
		history.setDisposable();
		super.ERROR(problemMessage);
	}

	@Override
	protected CT createConstraint() {
		return history.record(super.createConstraint());
	}

	@Override
	protected ExpressionInOCL createExpressionInOCL() {
		return history.record(super.createExpressionInOCL());
	}

	@Override
	protected boolean isErrorNode(TypedElement expr) {
		return history.isErrorNode(expr);
	}

	@Override
	protected void markAsErrorNode(TypedElement expr) {
		history.markAsErrorNode(expr);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy