Mercurial Hosting > nabble
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nabble/naml/compiler/Source.java Thu Mar 21 19:15:52 2019 -0600 @@ -0,0 +1,154 @@ +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()); + } +}