PARSER_BEGIN(IlrRuledefParser)

package ilog.rules.engine.ruledef.parser;


import ilog.rules.engine.lang.parser.*;
import ilog.rules.engine.lang.syntax.*;
import ilog.rules.engine.ruledef.syntax.*;
import com.ibm.rules.engine.util.*;
import java.util.*;
import java.io.*;


/**
 * <p>This is the class of a ruledef parser.</p>
 *
 * @author Hugues Citeau
 * @since  7up
 */
public class IlrRuledefParser {

    private IlrRuledefParserHelper<Token> helper = new IlrRuledefParserHelper<Token>();

    private IlrLanguageParserConfig config = (Platform.CSHARP ?
					      new IlrCSharpParserConfig() :
					      new IlrJavaParserConfig());

    /**
     * <p>Creates the link from the token manager to the parser so that
     * the configuration is available from the token manager in order
     * to change token recognition.</p>
     */
    private final void initTokenManager() {
	this.token_source.parser = this;
    }

    /**
     * <p>Creates a new ruledef parser.</p>
     * <p>This method should be prefered to constructor because it automatically
     * calls initTokenManager() on the new instance.</p>
     *
     * @param reader  The reader.
     * @return        the new ruledef parser.
     */ 
    public static IlrRuledefParser create(Reader reader) {
	IlrRuledefParser parser = new IlrRuledefParser(reader);

	parser.initTokenManager();
	return parser;
    }

    /**
     * <p>Gets the platform-specific parsing configuration.</p>
     *
     * @return  the configuration.
     */
    public final IlrLanguageParserConfig getConfig() {
	return this.config;
    }

    /**
     * <p>Notifies that a parse exception has occured.</p>
     *
     * @param exception  The exception.
     */
    public void notifyParseException(ParseException exception) {
	String      message = exception.getMessage();
	IlrSynError error = new IlrSynError(null,message);

	this.helper.addError(error);
    }

    /**
     * <p>Notifies that a token manager error has occured.</p>
     *
     * @param error  The error.
     */
    public void notifyTokenMgrError(TokenMgrError error) {
	String      message = error.getMessage();
	IlrSynError synError = new IlrSynError(null,message);

	this.helper.addError(synError);
    }

    /**
     * <p>Tells whether syntax errors have been detected during parsing.</p>
     *
     * @return  the result of the test.
     */
    public boolean hasErrors() {
	return (this.helper.getErrorCount() != 0);
    }

    /**
     * <p>Gets all the syntax errors that have been detected during the parsing.</p>
     *
     * @return  the errors.
     */
    public IlrSynError[] getErrors() {
	return this.helper.getErrors();
    }

    /**
     * <p>Clears all the syntax errors that have been detected during the last parsing.</p>
     */
    public void clearErrors() {
	this.helper.clearErrors();
    }

    /**
     * <p>Skips tokens until the brace level is back to the target
     * brace level when attempting to recover from a parse exception.</p>
     * <p>Note that this method has to be declared in the generated parser
     * and unfortunately not in the reusable helper because the getNextToken()
     * method and the keyword constants are generated.</p>
     *
     * @param targetBraceLevel  The target brace level.
     */
    public void skipTokensUntilBracesAreClosed(int targetBraceLevel) {
	Token token = null;

	for (;;) {
	    token = getNextToken();
	    if (token.kind == EOF)
		break;
	    else if (token.kind == SEMICOLON)
		break;
	    else if (token.kind == LBRACE)
		this.helper.incrementBraceLevel();
	    else if (token.kind == RBRACE) {
		if (this.helper.getBraceLevel() <= targetBraceLevel)
		    break;
		else {
		    this.helper.decrementBraceLevel();
		    if (this.helper.getBraceLevel() == targetBraceLevel)
			break;
		}
	    }
	}
    }

    public Token skipTokensUntil(int... kinds) {
	for (;;) {
	    Token token = getNextToken();

	    if (token.kind == EOF)
		return null;
	    else {
		for (int kind : kinds) {
		    if (token.kind == kind)
			return token;
		}
	    }
	}
    }

    /**
     * <p>Parses the name of type.</p>
     * <p>The result is null when syntax errors are detected.</p>
     *
     * @return  the AST of the name of the type.
     */
    public IlrSynType parseType() {
	IlrSynType type = null;

	try {
	    type = Type();
	}
	catch (ParseException exception) {
	    notifyParseException(exception);
	}
	catch (TokenMgrError error) {
	    notifyTokenMgrError(error);
	}
	if (hasErrors())
	    return null;
	else
	    return type;
    }

    /**
     * <p>Parses a value.</p>
     * <p>The result is null when syntax errors are detected.</p>
     *
     * @return  the AST of the value.
     */
    public IlrSynValue parseValue() {
	IlrSynValue value = null;

	try {
	    value = Expression();
	}
	catch (ParseException exception) {
	    notifyParseException(exception);
	}
	catch (TokenMgrError error) {
	    notifyTokenMgrError(error);
	}
	if (hasErrors())
	    return null;
	else
	    return value;
    }

    /**
     * <p>Parses a statement.</p>
     * <p>The result is null when syntax errors are detected.</p>
     *
     * @return  the AST of the statement.
     */
    public IlrSynStatement parseStatement() {
	IlrSynStatement statement = null;

	try {
	    statement = Statement();
	}
	catch (ParseException exception) {
	    notifyParseException(exception);
	}
	catch (TokenMgrError error) {
	    notifyTokenMgrError(error);
	}
	if (hasErrors())
	    return null;
	else
	    return statement;
    }

    /**
     * <p>Parses a declaration.</p>
     * <p>The result is null when syntax errors are detected.</p>
     *
     * @return  the AST of the declaration.
     */
    public IlrSynDeclaration parseDeclaration() {
	IlrSynDeclaration declaration = null;

	try {
	    declaration = Declaration();
	}
	catch (ParseException exception) {
	    notifyParseException(exception);
	}
	catch (TokenMgrError error) {
	    notifyTokenMgrError(error);
	}
	if (hasErrors())
	    return null;
	else
	    return declaration;
    }

    /**
     * <p>Parses a compilation unit.</p>
     * <p>The result is null when when syntax errors are detected.</p>
     *
     * @param identifier  The identifier of the compilation unit.
     * @return            the AST of the compilation unit.
     */
    public IlrSynCompilationUnit parseCompilationUnit(String identifier) {
	IlrSynCompilationUnit unit = null;

	try {
	    unit = CompilationUnit(identifier);
	}
	catch (ParseException exception) {
	    notifyParseException(exception);
	}
	catch (TokenMgrError error) {
	    notifyTokenMgrError(error);
	}
	if (hasErrors())
	    return null;
	else
	    return unit;
    }

    /**
     * <p>Entry point for quick testing purpose.</p>
     *
     * @param args  The arguments.
     */
    public static void main(String[] args) {
	if (args.length != 1)
	    System.err.println("Usage IlrRuledefParser.main <fileName>");
	else {
	    String fileName = args[0];

	    try {
		FileReader            reader = new FileReader(fileName);
		IlrRuledefParser      parser = IlrRuledefParser.create(reader);
		IlrSynCompilationUnit unit = parser.parseCompilationUnit(fileName);

		if (unit != null)
		    System.out.println("Parsing of :" + fileName + " succeeded");
		else {
		    IlrSynError[] errors = parser.getErrors();

		    System.err.println("Parsing of :" + fileName + " failed");
		    for (int i = 0; i < errors.length; i++) {
			IlrSynError        error = errors[i];
			System.err.println(error.getMessageWithLocation());
			}
			}
	    }
	    catch (FileNotFoundException exception) {
		System.err.println("File not found: " + fileName);
	    }
	}
    }
}

PARSER_END(IlrRuledefParser)


TOKEN_MGR_DECLS :
{
    public IlrRuledefParser parser;  // The link from the token manager to the parser to reach the config
}

