//{HEADER
/**
* This class is part of jnex 'Nexirius Application Framework for Java'
*
* Copyright (C) Nexirius GmbH, CH-4450 Sissach, Switzerland (www.nexirius.ch)
*
* <p>This library is free software; you can redistribute it and/or<br>
* modify it under the terms of the GNU Lesser General Public<br>
* License as published by the Free Software Foundation; either<br>
* version 2.1 of the License, or (at your option) any later version.</p>
*
* <p>This library is distributed in the hope that it will be useful,<br>
* but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU<br>
* Lesser General Public License for more details.</p>
*
* <p>You should have received a copy of the GNU Lesser General Public<br>
* License along with this library; if not, write to the Free Software<br>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</p>
* </blockquote>
*
* <p>
* Nexirius GmbH, hereby disclaims all copyright interest in<br>
* the library jnex' 'Nexirius Application Framework for Java' written<br>
* by Marcel Baumann.</p>
*/
//}HEADER
package com.nexirius.framework.datamodel.parser;
import com.nexirius.framework.datamodel.DataModel;
import com.nexirius.framework.dataviewer.DataViewer;
import com.nexirius.framework.dataviewer.ViewerFactory;
import com.nexirius.util.TextToken;
import com.nexirius.util.resource.ClientResource;
import com.nexirius.util.resource.ClientResourceImpl;
import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/*
Type: (Class | Enum)*
Class: ClassHeader ClassBody
ClassHeader: class Identifier StringLiteral
ClassBody: { ClassElement* }
ClassElement: Method | SimpleMember | ArrayMember
Method: Identifier Identifier();
SimpleMember: Identifier Identifier ;
| Identifier Identifier = StringLiteral ;
ArrayMember: Identifier Identifier [];
Enum: { StringLiteral* }
*/
/**
* A class which parses the DataModel syntax definition
*
* @author Marcel Baumann
*/
public class DataModelParser {
public static final char OCURLY = '{';
public static final char CCURLY = '}';
public static final char OBRACE = '(';
public static final char CBRACE = ')';
public static final char OBRACKET = '[';
public static final char CBRACKET = ']';
public static final char SEMICOLON = ';';
public static final char ASSIGN = '=';
public static final String CLASS = "class";
public static final String STRING = "String";
public static final String INTEGER = "Integer";
public static final String FLOAT = "Float";
public static final String DATE = "Date";
public static final String TIME = "Time";
public static final String TIMESTAMP = "TimeStamp";
public static final String BOOLEAN = "Boolean";
public static final String ENUM = "enum";
public static final String VOID = "void";
public final String basicType[] =
{
STRING, INTEGER, FLOAT, DATE, TIME, TIMESTAMP, BOOLEAN, ENUM, VOID
};
public final int basicTypeCode[] =
{
1, 2, 5, 6, 8, 7, 3, 4, 1000
};
TextToken tokens[] = null;
int currentToken = -1;
int numTokens;
DataModelClasses types;
DataModelTypeClass currentClass;
public DataModelParser() {
}
public void doPrint(String s) {
//System.out.println(s);
}
public DataModelClasses parse(String src)
throws Exception {
tokens = TextToken.getTokensFrom(src);
numTokens = tokens.length;
if (numTokens == 0) {
throw new Exception("No tokens or parser error while parsing '" + src + "'");
}
types = new DataModelClasses();
while (parseType()) {
}
return types;
}
boolean parseType()
throws Exception {
try {
// check whether the next token is a 'class' or 'enum'
TextToken t = nextToken();
if (t.isIdentifier(CLASS)) {
pushbackToken();
return parseClass();
}
if (t.isIdentifier(ENUM)) {
pushbackToken();
return parseEnum();
}
throw new SyntaxException("class or enum", t.debugString());
} catch (NoMoreTokensException ex) {
return false;
}
}
boolean parseEnum()
throws Exception {
try {
// check whether the next token is a 'enum'
TextToken t = nextToken();
if (!t.isIdentifier(ENUM)) {
throw new SyntaxException(ENUM, t.debugString());
}
t = nextToken();
if (!t.isIdentifier()) {
throw new SyntaxException("enum name", t.debugString());
}
//System.out.println("parsing enum " + t.getString());
DataModelTypeEnum e = new DataModelTypeEnum(t.getString());
t = nextToken();
if (!t.isChar(OCURLY)) {
throw new SyntaxException(OCURLY, t.debugString());
}
t = nextToken();
while (true) {
if (t.isChar(CCURLY)) {
break;
}
if (!t.isString()) {
throw new SyntaxException("enum value (string literal)", t.debugString());
}
e.addValue(t.getString());
t = nextToken();
}
types.add(e);
return true;
} catch (NoMoreTokensException ex) {
throw new Exception("No more tokens while parsing enum");
}
}
boolean parseClass()
throws Exception {
if (parseClassHeader()) {
parseClassBody();
types.add(currentClass);
currentClass = null;
return true;
}
return false;
}
boolean parseClassHeader()
throws Exception {
try {
// check whether the next token is a 'class'
TextToken t = nextToken();
if (!t.isIdentifier(CLASS)) {
throw new SyntaxException(CLASS, t.debugString());
}
t = nextToken();
if (!t.isIdentifier()) {
throw new SyntaxException("class name", t.debugString());
}
//System.out.println("parsing class " + t.getString());
currentClass = new DataModelTypeClass(t.getString());
t = nextToken();
if (t.isString()) {
currentClass.setImplementedBy(t.getString());
} else {
pushbackToken();
}
} catch (NoMoreTokensException ex) {
//ex.printStackTrace();
return false;
}
return true;
}
boolean parseClassBody()
throws Exception {
try {
TextToken t = nextToken();
if (!t.isChar(OCURLY)) {
throw new SyntaxException(OCURLY, t.debugString());
}
while (true) {
t = nextToken();
if (t.isChar(CCURLY)) {
break;
}
pushbackToken();
parseClassElement();
}
} catch (NoMoreTokensException ex) {
return false;
}
return true;
}
void parseClassElement()
throws Exception {
// check whether the next token is a Identifier
TextToken t = nextToken();
if (!t.isIdentifier()) {
throw new SyntaxException("type specifier", t.debugString());
}
String type = t.getString();
t = nextToken();
if (t.isIdentifier()) {
// simple member of array member or method
String memberName = t.getString();
t = nextToken();
if (t.isChar(OBRACKET)) {
t = nextToken();
if (!t.isChar(CBRACKET)) {
throw new SyntaxException(CBRACKET, t.debugString());
}
currentClass.append(new DataModelTypeArray(type, memberName));
} else if (t.isChar(OBRACE)) {
t = nextToken();
if (!t.isChar(CBRACE)) {
throw new SyntaxException(CBRACE, t.debugString());
}
currentClass.append(new DataModelTypeMethod(type, memberName));
} else if (t.isChar(SEMICOLON)) {
currentClass.append(new DataModelTypeMember(type, memberName, null));
pushbackToken();
} else if (t.isChar(ASSIGN)) {
t = nextToken();
if (!t.isString()) {
throw new SyntaxException("string literal (init value)", t.debugString());
}
currentClass.append(new DataModelTypeMember(type, memberName, t.getString()));
} else {
throw new SyntaxException("( or [ or ; or =", t.debugString());
}
t = nextToken();
if (!t.isChar(SEMICOLON)) {
throw new SyntaxException(SEMICOLON, t.debugString());
}
} else {
throw new SyntaxException("member name", t.debugString());
}
}
TextToken nextToken()
throws Exception {
++currentToken;
if (currentToken < numTokens) {
return tokens[currentToken];
}
throw new NoMoreTokensException();
}
void pushbackToken()
throws Exception {
if (currentToken < 0) {
throw new CantPushbackException();
}
--currentToken;
}
class SyntaxException extends Exception {
SyntaxException(String expect, String have) {
super("Expecting " + expect + " have: " + have);
}
SyntaxException(char expect, String have) {
super("Expecting Character '" + expect + "' have: " + have);
}
}
class NoMoreTokensException extends Exception {
NoMoreTokensException() {
super("No more tokens");
}
}
class CantPushbackException extends Exception {
CantPushbackException() {
super("Can't pushback token");
}
}
public static void main(String argv[]) {
String src = ""
+ "enum X {\"a\" \"b\"} "
+ "class Inner { "
+ " String string = \"hello\"; "
+ " Integer int = \"2000\"; "
+ "} "
+ "class TestModel \"com.nexirius.framework.datamodel.parser.TestModel\" { "
+ " Inner inner; "
+ " String name = \"Marcel Baumann\"; "
+ " X enum = \"b\"; "
+ " X func(); "
+ " Inner arr[]; "
+ " Rechnungen rechnungen; "
+ "} "
+ "class Rechnung { "
+ " String firma; "
+ " String nummer; "
+ " String titel; "
+ " Date datum; "
+ " Integer betrag; "
+ " Date zdatum; "
+ " Integer zbetrag; "
+ "} "
+ "class Rechnungen { "
+ " Rechnung rechnung[]; "
+ "} "
;
try {
DataModelParser p = new DataModelParser();
DataModelClasses classes = p.parse(src);
DataModel model = classes.newInstance("TestModel", null);
System.out.println(model.dragData());
JFrame frame = new JFrame();
frame.addWindowListener(new MyWindowListener());
ClientResource res = new ClientResourceImpl("TestClient");
ViewerFactory factory = new ViewerFactory(res);
factory.setCommandProcessor(new com.nexirius.framework.command.DefaultProcessor());
DataViewer v = factory.createDefaultEditor(model);
frame.getContentPane().add(v.getJComponent());
frame.pack();
frame.setVisible(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
class MyWindowListener extends WindowAdapter {
public void windowClosing(WindowEvent e) {
try {
System.exit(0);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}