001/*
002 * Copyright (C) 2009-2011 Mathias Doenitz
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.parboiled.parser;
018
019import org.parboiled.parserunners.ParseRunner;
020import org.parboiled.transform.ParserTransformer;
021import org.parboiled.parserunners.ParseRunner;
022
023import java.lang.reflect.Constructor;
024
025import static org.parboiled.common.Preconditions.checkArgNotNull;
026import static org.parboiled.common.Utils.findConstructor;
027
028/**
029 * Main class providing the high-level entry point into the parboiled library.
030 */
031public class Parboiled {
032
033    protected Parboiled() {}
034
035    /**
036     * <p>Creates a parser object whose rule creation methods can then be used with one of the {@link ParseRunner} implementations.</p>
037     * <p>Since parboiled needs to extend your parser with certain extra logic (e.g. to prevent infinite recursions
038     * in recursive rule definitions) you cannot create your parser object yourself, but have to go through this method.
039     * Also your parser class has to be derived from {@link BaseParser}. If you want to use a non-default constructor
040     * you can provide its arguments to this method. Make sure your non-default constructor does not use primitive
041     * type parameters (like "int") but rather their boxed counterparts (like "Integer"), otherwise the constructor
042     * will not be found.</p>
043     * <p>Performing the rule analysis and extending the parser class is an expensive process (time-wise) and can
044     * take up to several hundred milliseconds for large grammars. However, this cost is only incurred once per
045     * parser class and class loader. Subsequent calls to this method are therefore fast once the initial extension
046     * has been performed.</p>
047     *
048     * @param parserClass     the type of the parser to create
049     * @param constructorArgs optional arguments to the parser class constructor
050     * @return the ready to use parser instance
051     */
052    @SuppressWarnings({"unchecked"})
053    public static <P extends BaseParser<V>, V> P createParser(Class<P> parserClass, Object... constructorArgs) {
054        checkArgNotNull(parserClass, "parserClass");
055        try {
056            Class<?> extendedClass = ParserTransformer.transformParser(parserClass);
057            Constructor constructor = findConstructor(extendedClass, constructorArgs);
058            return (P) constructor.newInstance(constructorArgs);
059        } catch (Exception e) {
060            throw new RuntimeException("Error creating extended parser class: " + e.getMessage(), e);
061        }
062    }
063
064}