Mercurial Hosting > nabble
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 } |