Mercurial Hosting > nabble
view src/nabble/naml/compiler/Source.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children |
line wrap: on
line source
package nabble.naml.compiler; import fschmidt.util.java.Interner; import nabble.naml.dom.Container; import nabble.naml.dom.Element; import nabble.naml.dom.ElementName; import nabble.naml.dom.Naml; import nabble.naml.dom.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Arrays; public final class Source implements Comparable<Source> { public final String id; public final String content; private final Set<ElementName> ignoreTags; private List<Macro> macros = null; private Set<String> staticNames = null; private Source(String id,String content,Set<ElementName> ignoreTags) { this.id = id; this.content = content; this.ignoreTags = ignoreTags; } @Override public boolean equals(Object obj) { if( !(obj instanceof Source) ) return false; Source source = (Source)obj; return source.id.equals(id) && source.content.equals(content); } @Override public int hashCode() { return content.hashCode(); } @Override public int compareTo(Source source) { if( this == source ) return 0; int rtn = id.compareTo(source.id); if( rtn != 0 ) return rtn; return content.compareTo(source.content); } @Override public String toString() { return id; } public Collection<Macro> getMacros() throws CompileException { compile(); return macros; } Collection<String> staticNames() throws CompileException { compile(); return staticNames; } private static final Set<ElementName> macroNames = new LinkedHashSet<ElementName>(Arrays.asList( new ElementName( Macro.Type.MACRO.tagName ), new ElementName( Macro.OVERRIDE_PREFIX + Macro.Type.MACRO.tagName ), new ElementName( Macro.Type.SUBROUTINE.tagName ), new ElementName( Macro.OVERRIDE_PREFIX + Macro.Type.SUBROUTINE.tagName ), new ElementName( Macro.Type.TRANSLATION.tagName ), new ElementName( Macro.OVERRIDE_PREFIX + Macro.Type.TRANSLATION.tagName ), new ElementName( Macro.Type.NAMESPACE.tagName ) ) ); private static final ElementName staticName = new ElementName("static"); public Naml parse() throws CompileException { StackTrace stackTrace = new StackTrace(); try { return Naml.parser().parse(content); } catch(ParseException e) { stackTrace.push( new StackTraceElement(this,e.lineNumber) ); try { throw new CompileException(stackTrace,"parse exception in "+id+" - "+e.getMessage(),e); } finally { stackTrace.pop(); } } } private synchronized void compile() throws CompileException { if( macros != null ) return; List<Macro> macros = new ArrayList<Macro>(); staticNames = new HashSet<String>(); StackTrace stackTrace = new StackTrace(); Map<String,Integer> macroCount = new HashMap<String,Integer>(); for( Object obj : parse() ) { if( obj instanceof Element ) { Element element = (Element)obj; stackTrace.push( new StackTraceElement(this,element) ); try { ElementName tagName = element.name(); if( tagName.equals(staticName) ) { if( !(element instanceof Container) ) throw new CompileException(stackTrace,"empty '"+tagName+"' not allowed"); Container container = (Container)element; Naml staticNaml = container.contents(); if( staticNaml.isEmpty() ) throw new CompileException(stackTrace,"static tag may not be empty"); if( staticNaml.size() > 1 ) throw new CompileException(stackTrace,"static tag may only contain a list of names"); Object objS = staticNaml.get(0); if( !(objS instanceof String) ) throw new CompileException(stackTrace,"static tag may only contain a list of names"); String names = (String)objS; for( String name : names.split("\\s+") ) { name = name.toLowerCase(); staticNames.add(name); } continue; } if( macroNames.contains(tagName) ) { Macro macro = new Macro(this,element,stackTrace,macroCount); macros.add(macro); } else if( !ignoreTags.contains(tagName) ) { Set<ElementName> allowed = new LinkedHashSet<ElementName>(); allowed.addAll(macroNames); allowed.add(staticName); allowed.addAll(ignoreTags); throw new CompileException(stackTrace,"'"+tagName+"' not valid, only "+allowed+" tags allowed at root"); } } finally { stackTrace.pop(); } } } this.macros = macros; } private static final Interner<Source> interner = new Interner<Source>(); public static Source getInstance(String id,String content,Set<ElementName> ignoreTags) { return interner.intern(new Source(id,content,ignoreTags)); } public static Source getInstance(String id,String content) { return getInstance(id,content,Collections.<ElementName>emptySet()); } }