/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //$Revision$ $Date$ header { package org.apache.commons.flatfile.dsl; import java.io.IOException; import java.util.List; import java.util.Stack; import java.util.Iterator; import java.util.ArrayList; import java.util.HashMap; import org.apache.commons.flatfile.*; import org.apache.commons.flatfile.util.ApplyOptions; } class EntityTreeParser extends TreeParser; options { importVocab = Entity; defaultErrorHandler = false; codeGenBitsetTestThreshold=999; } { private java.lang.ref.WeakReference entityFactoryRef; private Stack stk = new Stack(); public synchronized Entity createEntity(EntityDefinition def) { String name = def.getName(); if (stk.contains(def.getName())) { throw new IllegalStateException("Circular reference detected for entity type " + name); } stk.push(def.getName()); try { Entity result = entity(def.getAst()); runChecks(def, result); return result; } catch (ANTLRException e) { throw new RuntimeException(e); } finally { String x = stk.pop(); if (!x.equals(def.getName())) { throw new IllegalStateException("Stack out of balance; encountered " + x); } } } public void setEntityFactory(ParserEntityFactory entityFactory) { this.entityFactoryRef = new java.lang.ref.WeakReference(entityFactory); } private void runChecks(EntityDefinition def, Entity e) { for (AST check : def.getChecks()) { switch (check.getType()) { case LENGTH : int expected = Integer.parseInt(check.getText()); int actual = e.length(); if (expected != actual) { throw new IllegalStateException( "expected entity " + def.getName() + " length=" + expected + "; actually " + actual); } break; default : throw new IllegalArgumentException("Unknown check: " + check); } } } private byte[] getBytes(String s) { try { return s.getBytes("UTF-8"); } catch (IOException e) { throw new RuntimeException(e); } } private ParserEntityFactory getEntityFactory() { return entityFactoryRef.get(); } } /* public */ load { List checks = new ArrayList(); String name = null; } : #( ROOT ( defaultOptions )* ( #( ASSIGN name=name e:. ) ( CHECK c:. { checks.add(c); } )* { EntityDefinition ed = new EntityDefinition(name, e); if (!checks.isEmpty()) { ed.setChecks(new ArrayList(checks)); checks.clear(); } getEntityFactory().add(name, ed); } )+ ) ; protected defaultOptions { HashMap m = new HashMap(); String key = null, value = null; } : #( o:OPTIONS ( #( ASSIGN key=optionKV value=optionKV { m.put(key, value); } ) )+ ) { getEntityFactory().setDefaultOptions(o.getText(), m); } ; protected entity returns [Entity e = null] : e=array | e=field | e=map | e=typeRef ; protected name returns [String s = null] : i:IDENT { s = i.getText(); } | ANON //let remain null ; protected typeRef returns [Entity e = null] : #(t:TYPEREF { e = getEntityFactory().getEntity(t.getText()); } ( entityOptions[e] )? ( e=value[e] )? ) ; protected array returns [IndexedEntityCollection a = null] { Entity prototype = null, e = null; Integer len = null, min = null, max = null; } : #( ARRAY ( l:LENGTH { len = Integer.valueOf(l.getText()); } | #(RANGE ( m:MIN { min = Integer.valueOf(m.getText()); } )? ( n:MAX { max = Integer.valueOf(n.getText()); } )? ) )? #(PROTOTYPE prototype=entity) { a = new EntityArray(prototype); if (len != null) { ((EntityArray) a).setSize(len.intValue()); } else { if (min != null) { ((EntityArray) a).setMinimumSize(min.intValue()); } if (max != null) { ((EntityArray) a).setMaximumSize(max.intValue()); } } } ( entityOptions[a] )? ( e=value[a] { a = (IndexedEntityCollection) e; } )? ) ; protected value[Entity e] returns [Entity result = e] : ( a:ALL { e.fill(getBytes(a.getText())[0]); } | v:VALUE { e.setValue(getBytes(v.getText())); } ) ( result=immutable[e] )? ; exception catch [IOException exc] { throw new RuntimeException(exc); } protected field returns [Entity e = null] : #( FIELD e=fieldDef ) ; protected fieldDef returns [Entity e = null] : ( l:LENGTH { e = getEntityFactory().createField(Integer.parseInt(l.getText())); } ( entityOptions[e] )? ( e=value[e] )? | v:VALUE { e = getEntityFactory().createField(getBytes(v.getText())); } ( e=immutable[e] )? | #( RANGE { e = getEntityFactory().createDynamicField(); } ( n:MIN { ((DynamicField) e).getBounds().setMinimum(Integer.parseInt(n.getText())); } )? ( x:MAX { ((DynamicField) e).getBounds().setMaximum(Integer.parseInt(x.getText())); } )? ) ( v2:VALUE { e.setValue(getBytes(v2.getText())); } )? ) ; protected map returns [NamedEntityCollection m = new EntityMap()] { String name = null; Entity temp = null; } : #( MAP ( #(ASSIGN name=name temp=entity { ((EntityMap) m).add(name, temp); } ) )+ ( entityOptions[m] )? ( temp=value[m] { m = (NamedEntityCollection) temp; } )? ) ; protected immutable[Entity e] returns [Entity result = null] : IMMUTABLE { result = ImmutableEntity.of(e); } ; protected entityOptions[Entity e] : #( OPTIONS ( entityOption[e] )+ ) ; protected entityOption[Entity e] { String key = null, value = null; } : #( ASSIGN key=optionKV value=optionKV { ApplyOptions.apply(e, key, value); } ) ; protected optionKV returns [String result = null] : c:CHAR_LITERAL { result = c.getText(); } | s:STRING_LITERAL { result = s.getText(); } | n:NUMBER { result = n.getText(); } | i:IDENT { result = i.getText(); } ;