comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:7ecd1a4ef557
1 package nabble.naml.compiler;
2
3 import fschmidt.util.java.Interner;
4 import nabble.naml.dom.Container;
5 import nabble.naml.dom.Element;
6 import nabble.naml.dom.ElementName;
7 import nabble.naml.dom.Naml;
8 import nabble.naml.dom.ParseException;
9
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.LinkedHashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.Arrays;
20
21
22 public final class Source implements Comparable<Source> {
23 public final String id;
24 public final String content;
25 private final Set<ElementName> ignoreTags;
26 private List<Macro> macros = null;
27 private Set<String> staticNames = null;
28
29 private Source(String id,String content,Set<ElementName> ignoreTags) {
30 this.id = id;
31 this.content = content;
32 this.ignoreTags = ignoreTags;
33 }
34
35 @Override public boolean equals(Object obj) {
36 if( !(obj instanceof Source) )
37 return false;
38 Source source = (Source)obj;
39 return source.id.equals(id) && source.content.equals(content);
40 }
41
42 @Override public int hashCode() {
43 return content.hashCode();
44 }
45
46 @Override public int compareTo(Source source) {
47 if( this == source )
48 return 0;
49 int rtn = id.compareTo(source.id);
50 if( rtn != 0 )
51 return rtn;
52 return content.compareTo(source.content);
53 }
54
55 @Override public String toString() {
56 return id;
57 }
58
59 public Collection<Macro> getMacros() throws CompileException {
60 compile();
61 return macros;
62 }
63
64 Collection<String> staticNames() throws CompileException {
65 compile();
66 return staticNames;
67 }
68
69 private static final Set<ElementName> macroNames = new LinkedHashSet<ElementName>(Arrays.asList(
70 new ElementName( Macro.Type.MACRO.tagName ),
71 new ElementName( Macro.OVERRIDE_PREFIX + Macro.Type.MACRO.tagName ),
72 new ElementName( Macro.Type.SUBROUTINE.tagName ),
73 new ElementName( Macro.OVERRIDE_PREFIX + Macro.Type.SUBROUTINE.tagName ),
74 new ElementName( Macro.Type.TRANSLATION.tagName ),
75 new ElementName( Macro.OVERRIDE_PREFIX + Macro.Type.TRANSLATION.tagName ),
76 new ElementName( Macro.Type.NAMESPACE.tagName )
77 ) );
78 private static final ElementName staticName = new ElementName("static");
79
80 public Naml parse() throws CompileException {
81 StackTrace stackTrace = new StackTrace();
82 try {
83 return Naml.parser().parse(content);
84 } catch(ParseException e) {
85 stackTrace.push( new StackTraceElement(this,e.lineNumber) );
86 try {
87 throw new CompileException(stackTrace,"parse exception in "+id+" - "+e.getMessage(),e);
88 } finally {
89 stackTrace.pop();
90 }
91 }
92 }
93
94 private synchronized void compile() throws CompileException {
95 if( macros != null )
96 return;
97 List<Macro> macros = new ArrayList<Macro>();
98 staticNames = new HashSet<String>();
99 StackTrace stackTrace = new StackTrace();
100 Map<String,Integer> macroCount = new HashMap<String,Integer>();
101 for( Object obj : parse() ) {
102 if( obj instanceof Element ) {
103 Element element = (Element)obj;
104 stackTrace.push( new StackTraceElement(this,element) );
105 try {
106 ElementName tagName = element.name();
107 if( tagName.equals(staticName) ) {
108 if( !(element instanceof Container) )
109 throw new CompileException(stackTrace,"empty '"+tagName+"' not allowed");
110 Container container = (Container)element;
111 Naml staticNaml = container.contents();
112 if( staticNaml.isEmpty() )
113 throw new CompileException(stackTrace,"static tag may not be empty");
114 if( staticNaml.size() > 1 )
115 throw new CompileException(stackTrace,"static tag may only contain a list of names");
116 Object objS = staticNaml.get(0);
117 if( !(objS instanceof String) )
118 throw new CompileException(stackTrace,"static tag may only contain a list of names");
119 String names = (String)objS;
120 for( String name : names.split("\\s+") ) {
121 name = name.toLowerCase();
122 staticNames.add(name);
123 }
124 continue;
125 }
126 if( macroNames.contains(tagName) ) {
127 Macro macro = new Macro(this,element,stackTrace,macroCount);
128 macros.add(macro);
129 } else if( !ignoreTags.contains(tagName) ) {
130 Set<ElementName> allowed = new LinkedHashSet<ElementName>();
131 allowed.addAll(macroNames);
132 allowed.add(staticName);
133 allowed.addAll(ignoreTags);
134 throw new CompileException(stackTrace,"'"+tagName+"' not valid, only "+allowed+" tags allowed at root");
135 }
136 } finally {
137 stackTrace.pop();
138 }
139 }
140 }
141 this.macros = macros;
142 }
143
144
145 private static final Interner<Source> interner = new Interner<Source>();
146
147 public static Source getInstance(String id,String content,Set<ElementName> ignoreTags) {
148 return interner.intern(new Source(id,content,ignoreTags));
149 }
150
151 public static Source getInstance(String id,String content) {
152 return getInstance(id,content,Collections.<ElementName>emptySet());
153 }
154 }