krysalis-impus/src/java/org/krysalis/impus ASTUtil.java,NONE,1.1 ImpusException.java,NONE,1.1 ImpusLexer.java,NONE,1.1 ImpusParser.java,NONE,1.1 ImpusTokenTypes.java,NONE,1.1 ImpusTokenTypes.txt,NONE,1.1 Initializer.java,NONE,1.1 Main.java,NONE,1.1 SyntaxException.java,NONE,1.1 parser.g,NONE,1.1

[email protected]
Newsgroups gmane.comp.krysalis.sandbox
Message-ID <[email protected]>
Update of /cvsroot/metamorphosis/krysalis-impus/src/java/org/krysalis/impus
In directory sc8-pr-cvs1:/tmp/cvs-serv2271/src/java/org/krysalis/impus

Added Files:
	ASTUtil.java ImpusException.java ImpusLexer.java 
	ImpusParser.java ImpusTokenTypes.java ImpusTokenTypes.txt 
	Initializer.java Main.java SyntaxException.java parser.g 
Log Message:
Initial import of the impus project.

--- NEW FILE: ASTUtil.java ---
/*****************************************************************************
 * Copyright (C) The Krysalis project. All rights reserved.                  *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Krysalis Patchy         *
 * Software License version 1.1_01, a copy of which has been included        *
 * at the bottom of this file.                                               *
 *****************************************************************************/
package org.krysalis.impus;

import antlr.collections.AST;

/**
 * Help functions for dealing with AST nodes.
 *
 * @author Glen Stampoultzis (glens at apache.org)
 */
public class ASTUtil
        implements ImpusTokenTypes
{

    /**
     * Number of siblings including current
     */
    public static int getNumberOfSiblings( AST ast )
    {
        if (ast == null)
            return 0;

        int cnt = 1;
        while ( ast.getNextSibling() != null )
        {
            cnt++;
            ast = ast.getNextSibling();
        }
        return cnt;
    }


    /**
     *  Removes any special characters for instance strings are unquoted and
     *  escapted.  Longs have the L's removed etc...
     */
    public static String fixValue( AST valueAST )
    {
        String tokenText = valueAST.getText();
        String upTokenText = tokenText.toUpperCase();
        boolean containsLongSuffix = upTokenText.endsWith( "L" ) && valueAST.getType() == NUM_LONG;
        boolean containsFloatSuffix = ( upTokenText.endsWith( "F" ) || upTokenText.endsWith( "D" ) ) && ( valueAST.getType() == NUM_FLOAT || valueAST.getType() == NUM_DOUBLE );
        if ( valueAST.getType() == STRING_LITERAL || valueAST.getType() == CHAR_LITERAL )
            return convertEscapes( tokenText.substring( 1, tokenText.length() - 1 ) );
        else if ( valueAST.getType() == MINUS )
            return "-" + fixValue( valueAST.getFirstChild() );
        else if ( containsLongSuffix || containsFloatSuffix )
            return tokenText.substring( 0, tokenText.length() - 1 );
        else
            return tokenText;
    }

    /**
     * Unescapes a string.  That is \t is translated to a tab etc.
     */
    private static String convertEscapes( String s )
    {
        StringBuffer result = new StringBuffer();
        for ( int i = 0; i < s.length(); i++ )
        {
            if ( s.charAt( i ) == '\\' && i != s.length() - 1 )
            {
                switch ( s.charAt( i + 1 ) )
                {
                    case 'r':
                        result.append( '\r' );
                        break;
                    case 'n':
                        result.append( '\n' );
                        break;
                    case 't':
                        result.append( '\t' );
                        break;
                    case '\\':
                        result.append( "\\" );
                        break;
                    default:
                        throw new IllegalArgumentException( "Invalid escape: \\" + s.charAt( i + 1 ) );
                }
                i++;
            }
            else
            {
                result.append( s.charAt( i ) );
            }
        }
        return result.toString();
    }

}


/*
The Krysalis Patchy Software License, Version 1.1_01
Copyright (c) 2002 Nicola Ken Barozzi.  All rights reserved.

This Licence is compatible with the BSD licence as described and
approved by http://www.opensource.org/, and is based on the
Apache Software Licence Version 1.1.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
 notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.

3. The end-user documentation included with the redistribution,
if any, must include the following acknowledgment:
   "This product includes software developed for project
    Krysalis (http://www.krysalis.org/)."
Alternately, this acknowledgment may appear in the software itself,
if and wherever such third-party acknowledgments normally appear.

4. The names "Krysalis" and "Nicola Ken Barozzi" and
"Krysalis Centipede" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].

5. Products derived from this software may not be called "Krysalis",
"Krysalis Centipede", nor may "Krysalis" appear in their name,
without prior written permission of Nicola Ken Barozzi.

6. This software may contain voluntary contributions made by many
individuals, who decided to donate the code to this project in
respect of this licence.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE KRYSALIS PROJECT OR
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
====================================================================*/

--- NEW FILE: ImpusException.java ---
package org.krysalis.impus;

public class ImpusException extends RuntimeException
{
    public ImpusException( String message )
    {
        super( message );
    }
}

--- NEW FILE: ImpusLexer.java ---
// $ANTLR 2.7.2: "parser.g" -> "ImpusLexer.java"$

package org.krysalis.impus;

import java.io.InputStream;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.TokenStreamRecognitionException;
import antlr.CharStreamException;
import antlr.CharStreamIOException;
import antlr.ANTLRException;
import java.io.Reader;
import java.util.Hashtable;
import antlr.CharScanner;
import antlr.InputBuffer;
import antlr.ByteBuffer;
import antlr.CharBuffer;
import antlr.Token;
import antlr.CommonToken;
[...1193 lines suppressed...]
		data[1]=343597383760L;
		return data;
	}
	public static final BitSet _tokenSet_4 = new BitSet(mk_tokenSet_4());
	private static final long[] mk_tokenSet_5() {
		long[] data = new long[1025];
		data[0]=287948901175001088L;
		data[1]=541165879422L;
		return data;
	}
	public static final BitSet _tokenSet_5 = new BitSet(mk_tokenSet_5());
	private static final long[] mk_tokenSet_6() {
		long[] data = new long[1025];
		data[0]=70368744177664L;
		data[1]=481036337264L;
		return data;
	}
	public static final BitSet _tokenSet_6 = new BitSet(mk_tokenSet_6());
	
	}

--- NEW FILE: ImpusParser.java ---
// $ANTLR 2.7.2: "parser.g" -> "ImpusParser.java"$

package org.krysalis.impus;

import antlr.TokenBuffer;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.ANTLRException;
import antlr.LLkParser;
import antlr.Token;
import antlr.TokenStream;
import antlr.RecognitionException;
import antlr.NoViableAltException;
import antlr.MismatchedTokenException;
import antlr.SemanticException;
import antlr.ParserSharedInputState;
import antlr.collections.impl.BitSet;
import antlr.collections.AST;
import java.util.Hashtable;
import antlr.ASTFactory;
import antlr.ASTPair;
import antlr.collections.impl.ASTArray;

public class ImpusParser extends antlr.LLkParser       implements ImpusTokenTypes
 {

protected ImpusParser(TokenBuffer tokenBuf, int k) {
  super(tokenBuf,k);
  tokenNames = _tokenNames;
  buildTokenTypeASTClassMap();
  astFactory = new ASTFactory(getTokenTypeToASTClassMap());
}

public ImpusParser(TokenBuffer tokenBuf) {
  this(tokenBuf,2);
}

protected ImpusParser(TokenStream lexer, int k) {
  super(lexer,k);
  tokenNames = _tokenNames;
  buildTokenTypeASTClassMap();
  astFactory = new ASTFactory(getTokenTypeToASTClassMap());
}

public ImpusParser(TokenStream lexer) {
  this(lexer,2);
}

public ImpusParser(ParserSharedInputState state) {
  super(state,2);
  tokenNames = _tokenNames;
  buildTokenTypeASTClassMap();
  astFactory = new ASTFactory(getTokenTypeToASTClassMap());
}

	public final void objectDef() throws RecognitionException, TokenStreamException {
		
		returnAST = null;
		ASTPair currentAST = new ASTPair();
		AST objectDef_AST = null;
		
		{
		switch ( LA(1)) {
		case IDENT:
		{
			classDef();
			astFactory.addASTChild(currentAST, returnAST);
			break;
		}
		case LPAREN:
		{
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		AST tmp1_AST = null;
		tmp1_AST = astFactory.create(LT(1));
		astFactory.makeASTRoot(currentAST, tmp1_AST);
		match(LPAREN);
		{
		_loop4:
		do {
			if ((LA(1)==IDENT)) {
				assignment();
				astFactory.addASTChild(currentAST, returnAST);
			}
			else {
				break _loop4;
			}
			
		} while (true);
		}
		match(RPAREN);
		objectDef_AST = (AST)currentAST.root;
		returnAST = objectDef_AST;
	}
	
	public final void classDef() throws RecognitionException, TokenStreamException {
		
		returnAST = null;
		ASTPair currentAST = new ASTPair();
		AST classDef_AST = null;
		
		AST tmp3_AST = null;
		tmp3_AST = astFactory.create(LT(1));
		astFactory.addASTChild(currentAST, tmp3_AST);
		match(IDENT);
		{
		_loop7:
		do {
			if ((LA(1)==DOT)) {
				match(DOT);
				AST tmp5_AST = null;
				tmp5_AST = astFactory.create(LT(1));
				astFactory.addASTChild(currentAST, tmp5_AST);
				match(IDENT);
			}
			else {
				break _loop7;
			}
			
		} while (true);
		}
		classDef_AST = (AST)currentAST.root;
		returnAST = classDef_AST;
	}
	
	public final void assignment() throws RecognitionException, TokenStreamException {
		
		returnAST = null;
		ASTPair currentAST = new ASTPair();
		AST assignment_AST = null;
		
		AST tmp6_AST = null;
		tmp6_AST = astFactory.create(LT(1));
		astFactory.addASTChild(currentAST, tmp6_AST);
		match(IDENT);
		AST tmp7_AST = null;
		tmp7_AST = astFactory.create(LT(1));
		astFactory.makeASTRoot(currentAST, tmp7_AST);
		match(ASSIGN);
		rvalue();
		astFactory.addASTChild(currentAST, returnAST);
		assignment_AST = (AST)currentAST.root;
		returnAST = assignment_AST;
	}
	
	public final void rvalue() throws RecognitionException, TokenStreamException {
		
		returnAST = null;
		ASTPair currentAST = new ASTPair();
		AST rvalue_AST = null;
		
		switch ( LA(1)) {
		case CHAR_LITERAL:
		{
			AST tmp8_AST = null;
			tmp8_AST = astFactory.create(LT(1));
			astFactory.makeASTRoot(currentAST, tmp8_AST);
			match(CHAR_LITERAL);
			rvalue_AST = (AST)currentAST.root;
			break;
		}
		case MINUS:
		case NUM_INT:
		case NUM_LONG:
		case NUM_FLOAT:
		case NUM_DOUBLE:
		{
			{
			switch ( LA(1)) {
			case MINUS:
			{
				AST tmp9_AST = null;
				tmp9_AST = astFactory.create(LT(1));
				astFactory.makeASTRoot(currentAST, tmp9_AST);
				match(MINUS);
				break;
			}
			case NUM_INT:
			case NUM_LONG:
			case NUM_FLOAT:
			case NUM_DOUBLE:
			{
				break;
			}
			default:
			{
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
			number();
			astFactory.addASTChild(currentAST, returnAST);
			rvalue_AST = (AST)currentAST.root;
			break;
		}
		case STRING_LITERAL:
		{
			AST tmp10_AST = null;
			tmp10_AST = astFactory.create(LT(1));
			astFactory.makeASTRoot(currentAST, tmp10_AST);
			match(STRING_LITERAL);
			rvalue_AST = (AST)currentAST.root;
			break;
		}
		case LITERAL_true:
		{
			AST tmp11_AST = null;
			tmp11_AST = astFactory.create(LT(1));
			astFactory.addASTChild(currentAST, tmp11_AST);
			match(LITERAL_true);
			rvalue_AST = (AST)currentAST.root;
			break;
		}
		case LITERAL_false:
		{
			AST tmp12_AST = null;
			tmp12_AST = astFactory.create(LT(1));
			astFactory.addASTChild(currentAST, tmp12_AST);
			match(LITERAL_false);
			rvalue_AST = (AST)currentAST.root;
			break;
		}
		case LBRACK:
		{
			listValues();
			astFactory.addASTChild(currentAST, returnAST);
			rvalue_AST = (AST)currentAST.root;
			break;
		}
		case LPAREN:
		case IDENT:
		{
			objectDef();
			astFactory.addASTChild(currentAST, returnAST);
			rvalue_AST = (AST)currentAST.root;
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		returnAST = rvalue_AST;
	}
	
	public final void number() throws RecognitionException, TokenStreamException {
		
		returnAST = null;
		ASTPair currentAST = new ASTPair();
		AST number_AST = null;
		
		switch ( LA(1)) {
		case NUM_INT:
		{
			AST tmp13_AST = null;
			tmp13_AST = astFactory.create(LT(1));
			astFactory.makeASTRoot(currentAST, tmp13_AST);
			match(NUM_INT);
			number_AST = (AST)currentAST.root;
			break;
		}
		case NUM_LONG:
		{
			AST tmp14_AST = null;
			tmp14_AST = astFactory.create(LT(1));
			astFactory.makeASTRoot(currentAST, tmp14_AST);
			match(NUM_LONG);
			number_AST = (AST)currentAST.root;
			break;
		}
		case NUM_FLOAT:
		{
			AST tmp15_AST = null;
			tmp15_AST = astFactory.create(LT(1));
			astFactory.makeASTRoot(currentAST, tmp15_AST);
			match(NUM_FLOAT);
			number_AST = (AST)currentAST.root;
			break;
		}
		case NUM_DOUBLE:
		{
			AST tmp16_AST = null;
			tmp16_AST = astFactory.create(LT(1));
			astFactory.makeASTRoot(currentAST, tmp16_AST);
			match(NUM_DOUBLE);
			number_AST = (AST)currentAST.root;
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		returnAST = number_AST;
	}
	
	public final void listValues() throws RecognitionException, TokenStreamException {
		
		returnAST = null;
		ASTPair currentAST = new ASTPair();
		AST listValues_AST = null;
		
		AST tmp17_AST = null;
		tmp17_AST = astFactory.create(LT(1));
		astFactory.addASTChild(currentAST, tmp17_AST);
		match(LBRACK);
		{
		switch ( LA(1)) {
		case LPAREN:
		case IDENT:
		case CHAR_LITERAL:
		case MINUS:
		case STRING_LITERAL:
		case LITERAL_true:
		case LITERAL_false:
		case NUM_INT:
		case NUM_LONG:
		case NUM_FLOAT:
		case NUM_DOUBLE:
		case LBRACK:
		{
			rvalue();
			astFactory.addASTChild(currentAST, returnAST);
			{
			_loop15:
			do {
				if ((LA(1)==COMMA)) {
					match(COMMA);
					rvalue();
					astFactory.addASTChild(currentAST, returnAST);
				}
				else {
					break _loop15;
				}
				
			} while (true);
			}
			break;
		}
		case RBRACK:
		{
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		match(RBRACK);
		listValues_AST = (AST)currentAST.root;
		returnAST = listValues_AST;
	}
	
	
	public static final String[] _tokenNames = {
		"<0>",
		"EOF",
		"<2>",
		"NULL_TREE_LOOKAHEAD",
		"LPAREN",
		"RPAREN",
		"IDENT",
		"DOT",
		"ASSIGN",
		"CHAR_LITERAL",
		"MINUS",
		"STRING_LITERAL",
		"\"true\"",
		"\"false\"",
		"NUM_INT",
		"NUM_LONG",
		"NUM_FLOAT",
		"NUM_DOUBLE",
		"LBRACK",
		"COMMA",
		"RBRACK",
		"LCURLY",
		"RCURLY",
		"WS",
		"SL_COMMENT",
		"ML_COMMENT",
		"ESC",
		"HEX_DIGIT",
		"EXPONENT",
		"FLOAT_SUFFIX"
	};
	
	protected void buildTokenTypeASTClassMap() {
		tokenTypeToASTClassMap=null;
	};
	
	
	}

--- NEW FILE: ImpusTokenTypes.java ---
// $ANTLR 2.7.2: "parser.g" -> "ImpusLexer.java"$

package org.krysalis.impus;

public interface ImpusTokenTypes {
	int EOF = 1;
	int NULL_TREE_LOOKAHEAD = 3;
	int LPAREN = 4;
	int RPAREN = 5;
	int IDENT = 6;
	int DOT = 7;
	int ASSIGN = 8;
	int CHAR_LITERAL = 9;
	int MINUS = 10;
	int STRING_LITERAL = 11;
	int LITERAL_true = 12;
	int LITERAL_false = 13;
	int NUM_INT = 14;
	int NUM_LONG = 15;
	int NUM_FLOAT = 16;
	int NUM_DOUBLE = 17;
	int LBRACK = 18;
	int COMMA = 19;
	int RBRACK = 20;
	int LCURLY = 21;
	int RCURLY = 22;
	int WS = 23;
	int SL_COMMENT = 24;
	int ML_COMMENT = 25;
	int ESC = 26;
	int HEX_DIGIT = 27;
	int EXPONENT = 28;
	int FLOAT_SUFFIX = 29;
}

--- NEW FILE: ImpusTokenTypes.txt ---
// $ANTLR 2.7.2: parser.g -> ImpusTokenTypes.txt$
Impus    // output token vocab name
LPAREN=4
RPAREN=5
IDENT=6
DOT=7
ASSIGN=8
CHAR_LITERAL=9
MINUS=10
STRING_LITERAL=11
LITERAL_true="true"=12
LITERAL_false="false"=13
NUM_INT=14
NUM_LONG=15
NUM_FLOAT=16
NUM_DOUBLE=17
LBRACK=18
COMMA=19
RBRACK=20
LCURLY=21
RCURLY=22
WS=23
SL_COMMENT=24
ML_COMMENT=25
ESC=26
HEX_DIGIT=27
EXPONENT=28
FLOAT_SUFFIX=29

--- NEW FILE: Initializer.java ---
/*****************************************************************************
 * Copyright (C) The Krysalis project. All rights reserved.                  *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Krysalis Patchy         *
 * Software License version 1.1_01, a copy of which has been included        *
 * at the bottom of this file.                                               *
 *****************************************************************************/

package org.krysalis.impus;

import antlr.RecognitionException;
import antlr.collections.AST;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.krysalis.impus.ASTUtil;
import org.krysalis.impus.ImpusException;

import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Primary class for this module.  This class has one public function
 * <code>assign()</code>.  That allows the user to take short hand assignment
 * syntax and initialize javabeans.  For example:
 * <pre>
 * Initializer i = new Initializer();
 * i.assign( myVar, "(prop1=\"test\" prop2=20.9 prop3=true prop4=(x=2 y=5))");
 * </pre>
 * The code above assigns the properties prop1, prop2, prop3 and prop4 into
 * the object <code>myVar</code>.  Obviously a setter needs to be available
 * for the property or things just aren't going to work.
 * <p>
 * Arrays and collections can be initialized using the following syntax:
 * <pre>
 *  (myArray=[1,2,3])
 * </pre>
 * or
 * <pre>
 * (myArray=[ (x=1 y=2) (x=2 y=1) ] )
 * </pre>
 * or if the type can not be determined from the setter:
 * <pre>
 * (myArray=[ com.company.A(name="This is a name") ])
 * </pre>
 * The fully qualified class name can always be prepended when the required
 * type is unclear.
 *
 * @author Glen Stampoultzis
 */
public class Initializer
        implements ImpusTokenTypes
{
    /**
     * Assigns the values from the assignment language specifried in
     * <code>assignStmt</code> to the object passed to <code>source</code>.
     *
     * @param source     The source object to assign.
     * @param assignStmt The assignment statement (see class doc's for details).
     * @throws org.krysalis.impus.SyntaxException         Thrown when a syntax error occurs in the <code>assignStmt</code> minilanguage.
     * @throws org.krysalis.impus.ImpusException Thrown when the library is unable to assign to the <code>source</code>
     *                                 object due to some problem.
     */
    public void assign( Object source, String assignStmt ) throws SyntaxException, ImpusException
    {
        try
        {
            byte[] buf = assignStmt.getBytes();
            ByteArrayInputStream is = new ByteArrayInputStream( buf );
            ImpusLexer lexer = new ImpusLexer( is );
            ImpusParser parser = new ImpusParser( lexer );
            parser.objectDef();

            AST ast = parser.getAST();
            if ( ast.getType() == LPAREN )
            {
                if (ast.getFirstChild() != null && ast.getFirstChild().getType() == IDENT)
                    throw new ImpusException("Can not specify type for first object defintion.");
                else
                    makeObject( ast.getFirstChild(), source );
            }
            else
            {
                throw new IllegalArgumentException( "Illegal start of expression." );
            }
        }
        catch (RecognitionException e)
        {
            throw new SyntaxException(e.toString());
        }
        catch (ImpusException e)
        {
            throw e;
        }
        catch (ClassNotFoundException e)
        {
            throw new ImpusException("Could not find class: " + e.getMessage());
        }
        catch (InstantiationException e)
        {
            throw new ImpusException("Could not create class instance: " + e.getMessage());
        }
        catch (Exception e)
        {
            e.printStackTrace();
            throw new ImpusException("Unable to initialize object");
        }
    }

    /**
     * Sets thje properties of a particular object.
     *
     * @param equalsAST The first equals AST representing the property/value pairs in the program.
     * @param source    The object to assign the values into.
     */
    private void makeObject( AST equalsAST, Object source ) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, ClassNotFoundException
    {
        while ( equalsAST != null )
        {
            AST propAST = equalsAST.getFirstChild();
            AST valueAST = propAST.getNextSibling();
            String prop = propAST.getText();
            PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor( source, prop );
            if (propertyDescriptor == null)
                throw new ImpusException("Property setter for " + prop + " in class " + source.getClass().getName() + " not found.");
            Method writeMethod = propertyDescriptor.getWriteMethod();
            Class aClass = writeMethod.getParameterTypes()[0];
            Object value = makeValue( aClass, valueAST );
            BeanUtils.setProperty( source, prop, value );

            equalsAST = equalsAST.getNextSibling();
        }
    }

    /**
     * Creates a new object either by trying to infer it's type or by using
     * a type that was explicitly passed into parameter <code>aClass</code>
     *
     * @param aClass        An optional type specifying which instance to create.
     * @param valueAST      A reference to the valueAST for this object.
     * @return A newly instanciated object.
     */
    private Object makeValue( Class aClass, AST valueAST )
            throws NoSuchMethodException, InvocationTargetException,
            IllegalAccessException, InstantiationException, ClassNotFoundException
    {
        if ( valueAST.getType() == LBRACK )
        {
            return makeArray( aClass, valueAST.getNextSibling() );
        }
        else if ( valueAST.getType() == IDENT )
        {
            Class klass = Class.forName( classNameFromAST( valueAST ) );
            Object o = klass.newInstance();
            makeObject( skipIdents( valueAST ), o );
            return o;
        }
        else if ( valueAST.getType() == LPAREN )
        {
//            PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor( bean, propName );
//            Method writeMethod = propertyDescriptor.getWriteMethod();
//            Object o = writeMethod.getParameterTypes()[0].newInstance();
            if ( valueAST.getFirstChild() != null && valueAST.getFirstChild().getType() == IDENT)
            {
                return makeValue( null, valueAST.getFirstChild() );
            }
            else
            {
                Object o = aClass.newInstance();
                makeObject( skipIdents(valueAST.getFirstChild()), o );
                return o;
            }
        }
        else
        {
            if (aClass == null)
                throw new ImpusException("Could not create value.  Type unknown.");

            Object value = ConvertUtils.convert( ASTUtil.fixValue( valueAST ), aClass );
            return value;

//            return ASTUtil.fixValue( valueAST );
        }
    }

    /**
     * Skips past all IDENT tokens for those cases where we can safely ignore them.
     * @param ast   A reference to the first AST containing an IDENT
     * @return      The first AST after the IDENTS
     */
    private AST skipIdents( AST ast )
    {
        while ( ast != null && ast.getType() == IDENT )
            ast = ast.getNextSibling();
        return ast;
    }

    /**
     * Builds the class name from a list of IDENTS
     *
     * @param ast   A reference to the first AST containing an IDENT
     * @return      The fully qualified class name.
     */
    private String classNameFromAST( AST ast )
    {
        StringBuffer name = new StringBuffer();
        while ( ast != null && ast.getType() == IDENT )
        {
            if ( !name.toString().equals( "" ) )
                name.append( '.' );
            name.append( ast.getText() );
            ast = ast.getNextSibling();
        }
        return name.toString();
    }


    /**
     * Creates a list of array elements.
     *
     * @param aClass        The class of the array the array elements will be
     *                      placed into.
     * @param arrayStart    The starting point into the array.
     * @return              The array items.
     */
    private Object makeArray( Class aClass, AST arrayStart ) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, ClassNotFoundException
    {
        if ( Collection.class.isAssignableFrom( aClass ) )
        {
            List list = new ArrayList();
            while ( arrayStart != null )
            {
                list.add( wrapValue( arrayStart ) );
                arrayStart = arrayStart.getNextSibling();
            }
            return list;
        }
        else
        {
            return makeArrayItems( aClass.getComponentType(), arrayStart );
        }
    }

    /**
     * Converts primitive values into their wrapped equivalents.
     */
    private Object wrapValue( AST ast ) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException
    {
        if ( ast.getType() == Initializer.NUM_INT )
            return new Integer( ASTUtil.fixValue( ast ) );
        else if ( ast.getType() == Initializer.NUM_LONG )
            return new Long( ASTUtil.fixValue( ast ) );
        else if ( ast.getType() == Initializer.NUM_FLOAT )
            return new Float( ASTUtil.fixValue( ast ) );
        else if ( ast.getType() == Initializer.NUM_DOUBLE )
            return new Double( ASTUtil.fixValue( ast ) );
        else if ( ast.getType() == Initializer.STRING_LITERAL )
            return ASTUtil.fixValue( ast );
        else if ( ast.getType() == Initializer.CHAR_LITERAL )
            return new Character( ASTUtil.fixValue( ast ).charAt( 0 ) );
        else if ( ast.getType() == Initializer.LPAREN )
            return makeValue( null, ast.getFirstChild() );
        else
            return null;
    }

    /**
     * Creates an array of elements from an ast
     *
     * @param componentType The default element type
     * @param arrayStart    A pointer to the AST where the array starts.
     */
    private Object makeArrayItems( Class componentType, AST arrayStart ) throws InstantiationException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException
    {
        if (componentType == null)
            throw new ImpusException("Could not create array");
        int size = ASTUtil.getNumberOfSiblings( arrayStart );
        Object array = Array.newInstance( componentType, size );
        for ( int i = 0; i < Array.getLength( array ); i++ )
        {
//            Object value = ConvertUtils.convert( ASTUtil.fixValue( arrayStart ), componentType );
            Object value = makeValue(componentType, arrayStart);
            Array.set( array, i, value );
            arrayStart = arrayStart.getNextSibling();
        }
        return array;

        //      return null;
    }


}

/*
The Krysalis Patchy Software License, Version 1.1_01
Copyright (c) 2002 Nicola Ken Barozzi.  All rights reserved.

This Licence is compatible with the BSD licence as described and
approved by http://www.opensource.org/, and is based on the
Apache Software Licence Version 1.1.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
 notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.

3. The end-user documentation included with the redistribution,
if any, must include the following acknowledgment:
   "This product includes software developed for project
    Krysalis (http://www.krysalis.org/)."
Alternately, this acknowledgment may appear in the software itself,
if and wherever such third-party acknowledgments normally appear.

4. The names "Krysalis" and "Nicola Ken Barozzi" and
"Krysalis Centipede" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].

5. Products derived from this software may not be called "Krysalis",
"Krysalis Centipede", nor may "Krysalis" appear in their name,
without prior written permission of Nicola Ken Barozzi.

6. This software may contain voluntary contributions made by many
individuals, who decided to donate the code to this project in
respect of this licence.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE KRYSALIS PROJECT OR
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
====================================================================*/

--- NEW FILE: Main.java ---
/*****************************************************************************
 * Copyright (C) The Krysalis project. All rights reserved.                  *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Krysalis Patchy         *
 * Software License version 1.1_01, a copy of which has been included        *
 * at the bottom of this file.                                               *
 *****************************************************************************/

package org.krysalis.impus;

import antlr.collections.AST;
import antlr.debug.misc.ASTFrame;

import java.io.*;

import org.krysalis.impus.ImpusLexer;
import org.krysalis.impus.ImpusParser;

public class Main
{
      public static void main( String[] args )
      {
         try {
            String strBuf = "org.krysalis.impus.A()";
            byte[] buf = strBuf.getBytes();
//            byte[] buf = "(a = 1 b = 2)".getBytes();
            ByteArrayInputStream is = new ByteArrayInputStream(buf);
            ImpusLexer lexer = new ImpusLexer(is);
            ImpusParser parser = new ImpusParser(lexer);
            parser.objectDef();
            AST ast = parser.getAST();
            System.out.println( "ast = " + ast.toStringTree() );

            ASTFrame frame = new ASTFrame("AST JTree Example", ast);
            frame.setVisible(true);
            is.close();
         } catch(Exception e) {
            System.err.println("exception: "+e);
        }
      }
}


/*
The Krysalis Patchy Software License, Version 1.1_01
Copyright (c) 2002 Nicola Ken Barozzi.  All rights reserved.

This Licence is compatible with the BSD licence as described and
approved by http://www.opensource.org/, and is based on the
Apache Software Licence Version 1.1.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
 notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.

3. The end-user documentation included with the redistribution,
if any, must include the following acknowledgment:
   "This product includes software developed for project
    Krysalis (http://www.krysalis.org/)."
Alternately, this acknowledgment may appear in the software itself,
if and wherever such third-party acknowledgments normally appear.

4. The names "Krysalis" and "Nicola Ken Barozzi" and
"Krysalis Centipede" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].

5. Products derived from this software may not be called "Krysalis",
"Krysalis Centipede", nor may "Krysalis" appear in their name,
without prior written permission of Nicola Ken Barozzi.

6. This software may contain voluntary contributions made by many
individuals, who decided to donate the code to this project in
respect of this licence.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE KRYSALIS PROJECT OR
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
====================================================================*/

--- NEW FILE: SyntaxException.java ---
package org.krysalis.impus;

public class SyntaxException extends RuntimeException
{
    public SyntaxException( String message )
    {
        super( message );
    }
}

--- NEW FILE: parser.g ---
//*****************************************************************************
// * Copyright (C) The Krysalis project. All rights reserved.                  *
// * ------------------------------------------------------------------------- *
// * This software is published under the terms of the Krysalis Patchy         *
// * Software License version 1.1_01, a copy of which has been included        *
// * at the bottom of this file.                                               *
// *****************************************************************************/

header
{
package org.krysalis.impus;
}

class ImpusParser extends Parser;
options
{
	k = 2;                           // two token lookahead
	exportVocab=Impus;                // Call its vocabulary "Java"
	buildAST = true;
    defaultErrorHandler=false;
}


objectDef
    :   (classDef)? LPAREN^ (assignment)* RPAREN!
    ;

classDef
    :   IDENT (DOT! IDENT)*
    ;

assignment
    :   IDENT ASSIGN^ rvalue
    ;

rvalue
    :   CHAR_LITERAL^
    |   (MINUS^)? number
    |   STRING_LITERAL^
    |   "true"
    |   "false"
    |   listValues
    |   objectDef
    ;

number
    :   NUM_INT^
    |   NUM_LONG^
    |   NUM_FLOAT^
    |   NUM_DOUBLE^;

listValues
    :   LBRACK (rvalue ( COMMA! rvalue)*)? RBRACK!
    ;



//////////////////////////////////////////////////////////////////////////////

class ImpusLexer extends Lexer;
options
{
	exportVocab=Impus;
	testLiterals=false;            // don't automatically test for literals
    charVocabulary='\u0003'..'\uFFFF';
    k=5;                   // four characters of lookahead
}
//tokens
//{
   //DOT;
   //NUM_FLOAT;
   //NUM_DOUBLE;
   //NUM_LONG;
//}

LPAREN			:	'('		;
RPAREN			:	')'		;
LBRACK			:	'['		;
RBRACK			:	']'		;
LCURLY			:	'{'		;
RCURLY			:	'}'		;
ASSIGN			:	'='		;
COMMA			:	','		;
MINUS			:	'-'		;
//TRUE			:	"true"	;
//FALSE			:	"false"	;
//DOT			:	'.'		;

WS	:	(	' '
		|	'\t'
		|	'\f'
			// handle newlines
		|	(	options {generateAmbigWarnings=false;}
			:	"\r\n"  // Evil DOS
			|	'\r'    // Macintosh
			|	'\n'    // Unix (the right way)
			)
			{ newline(); }
		)+
		{ _ttype = Token.SKIP; }
	;


// Single-line comments
SL_COMMENT
	:	"//"
		(~('\n'|'\r'))* ('\n'|'\r'('\n')?)
		{$setType(Token.SKIP); newline();}
	;

// multiple-line comments
ML_COMMENT
	:	"/*"
		(	/*	'\r' '\n' can be matched in one alternative or by matching
				'\r' in one iteration and '\n' in another.  I am trying to
				handle any flavor of newline that comes in, but the language
				that allows both "\r\n" and "\r" and "\n" to all be valid
				newline is ambiguous.  Consequently, the resulting grammar
				must be ambiguous.  I'm shutting this warning off.
			 */
			options {
				generateAmbigWarnings=false;
			}
		:
			{ LA(2)!='/' }? '*'
		|	'\r' '\n'		{newline();}
		|	'\r'			{newline();}
		|	'\n'			{newline();}
		|	~('*'|'\n'|'\r')
		)*
		"*/"
		{$setType(Token.SKIP);}
	;

// character literals
CHAR_LITERAL
	:	'\'' ( ESC | ~'\'' ) '\''
	;

// string literals
STRING_LITERAL
	:	'"' (ESC|~('"'|'\\'))* '"'
	;

// escape sequence -- note that this is protected; it can only be called
//   from another lexer rule -- it will not ever directly return a token to
//   the parser
// There are various ambiguities hushed in this rule.  The optional
// '0'...'9' digit matches should be matched here rather than letting
// them go back to STRING_LITERAL to be matched.  ANTLR does the
// right thing by matching immediately; hence, it's ok to shut off
// the FOLLOW ambig warnings.
protected
ESC
	:	'\\'
		(	'n'
		|	'r'
		|	't'
		|	'b'
		|	'f'
		|	'"'
		|	'\''
		|	'\\'
		|	('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
		|	'0'..'3'
			(
				options {
					warnWhenFollowAmbig = false;
				}
			:	'0'..'7'
				(
					options {
						warnWhenFollowAmbig = false;
					}
				:	'0'..'7'
				)?
			)?
		|	'4'..'7'
			(
				options {
					warnWhenFollowAmbig = false;
				}
			:	'0'..'7'
			)?
		)
	;


// hexadecimal digit (again, note it's protected!)
protected
HEX_DIGIT
	:	('0'..'9'|'A'..'F'|'a'..'f')
	;

// an identifier.  Note that testLiterals is set to true!  This means
// that after we match the rule, we look in the literals table to see
// if it's a literal or really an identifer
IDENT
	options {testLiterals=true;}
	:	('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
	;

// a numeric literal
NUM_INT
	{boolean isDecimal=false; Token t=null;}
    :
	'.' {_ttype = DOT;}
        (
	    ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
            {
		if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
		    _ttype = NUM_FLOAT;
		} else {
                    _ttype = NUM_DOUBLE; // assume double
		}
	    }
        )?

    |
	(
	    '0' {isDecimal = true;} // special case for just '0'
	    (
		('x'|'X')
		(							// hex
		    // the 'e'|'E' and float suffix stuff look
		    // like hex digits, hence the (...)+ doesn't
		    // know when to stop: ambig.  ANTLR resolves
		    // it correctly by matching immediately.  It
		    // is therefor ok to hush warning.
		    options { warnWhenFollowAmbig=false; }
			    :	HEX_DIGIT
		)+
	    |
		('0'..'7')+					    // octal
	    )?
	|
	    ('1'..'9') ('0'..'9')*  {isDecimal=true;}		// non-zero decimal
	)
	(
	    ('l'|'L') { _ttype = NUM_LONG; }

	    // only check to see if it's a float if looks like decimal so far
	|	{isDecimal}?
            (
		'.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
            |
		EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
            |
		f4:FLOAT_SUFFIX {t=f4;}
            )
            {
	    	if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
		    _ttype = NUM_FLOAT;
		} else {
		    _ttype = NUM_DOUBLE; // assume double
		}
	    }
        )?
	;

// a couple protected methods to assist in matching floating point numbers
protected
EXPONENT
	:	('e'|'E') ('+'|'-')? ('0'..'9')+
	;


protected
FLOAT_SUFFIX
	:	'f'|'F'|'d'|'D'
	;

/*
The Krysalis Patchy Software License, Version 1.1_01
Copyright (c) 2002 Nicola Ken Barozzi.  All rights reserved.

This Licence is compatible with the BSD licence as described and
approved by http://www.opensource.org/, and is based on the
Apache Software Licence Version 1.1.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
 notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.

3. The end-user documentation included with the redistribution,
if any, must include the following acknowledgment:
   "This product includes software developed for project
    Krysalis (http://www.krysalis.org/)."
Alternately, this acknowledgment may appear in the software itself,
if and wherever such third-party acknowledgments normally appear.

4. The names "Krysalis" and "Nicola Ken Barozzi" and
"Krysalis Centipede" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].

5. Products derived from this software may not be called "Krysalis",
"Krysalis Centipede", nor may "Krysalis" appear in their name,
without prior written permission of Nicola Ken Barozzi.

6. This software may contain voluntary contributions made by many
individuals, who decided to donate the code to this project in
respect of this licence.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE KRYSALIS PROJECT OR
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
====================================================================*/




-------------------------------------------------------
This SF.net email is sponsored by:Crypto Challenge is now open! 
Get cracking and register here for some mind boggling fun and 
the chance of winning an Apple iPod:
http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0031en
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.