source: java/main/src/main/java/com/framsticks/parsers/F0Parser.java @ 98

Last change on this file since 98 was 98, checked in by psniegowski, 11 years ago

HIGHLIGHTS:

CHANGELOG:
Get data also on tree expansion.

Use nice framstick icon for empty nodes.

Update panel after reload if it is current.

Add shallow reload procedure.

Cut Gui prefix from several tree classes.

Bring back counter of GuiTreeNode?.

Use IdentityHashMap? were it is more appriopriate.

Remove TreeListener?.

Do not use TreeListener? in GUI.

Minor change.

Done migration to GuiTreeModel?.

BrowserTest? in that version always crashes frams.linux.

Move rendering implementation into GuiAbstractNode?.

Use hand-crafted list in GuiTreeNode?.

Generally, it would be a great place for WeakIdentityHashMap?
(but there is none in Java Collection Framework).

Remove superfluous logging.

Fix bug in GuiTreeNode?.

Use IdentityHashMap? instead of HashMap?.

Improve structure update.

Filter out invalid uids in UniqueListAccess?.

Improve TreeCellRenderer?.

Add filtering in TrackConsole?.

Improve TreeModel?.

More changes.

More improvements.

More changes.

Remove TreeNode?.

Support MetaNode? in the GuiTreeModel?.

Implement more in GuiTreeModel?.

Add CompositeParam? interface to FramsClass? and AccessInterface?.

Allow access by number to UniqueList?.

Add UidComparator?.

Use TreeMap? as a default accessee in unique list.

It keeps order of keys.

Introduce classes to use with new TreeModel?.

Another step.

Migrate from TreeNode? to Node in many places.

Remove some uses of TreeNode? as DefaultMutableTreeNode?.

Remove Path from TreeNode? interface.

Remove Path from TreeNode?.

Add Path recration from node feature.

Reworking TreeCellRenderer?.

Minor change of TreeOperations? interface.

Remove last methods from TreeNode?.

Another minor step.

Do not store reference to TreeAtFrame? in TreeNode?.

Add proxy exceptionHandler to StatusBar?.

Move panels management to TreeAtFrame?.

Store localChanges in the NodeAtFrame?.

More cleanup.

Move name computing to TreeCellRenderer?.

Move tooltip and icon computations to TreeCellRenderer?.

More dispatches removed.

Remove most dispatching from TreeNode?.

TreeNode? does not actually redispatch tasks.

Make Tree embedded in Browser use SwingDispatcher?.

Make lazy binding of Tree with Dispatcher.

Minor changes.

Organizational change in AbstractTree?.

Make AbstractTree? compose from Thread instead of inherit from it.

Make SwingDispatcher? and AtOnceDispatcher? Joinable compatible.

Add ListPanelProvider?.

Improve Controls readonly and enabled handling.

Properly pass ExceptionHandlers? in more places.

Make Tree.get accept ValueParam?.

  • This is to allow access number of list elements.

Remove not needed get redirection in ClientAtServer?.

Rename tryResolve to tryGet.

Unify tryResolveAndGet into tryResolve.

Remove resolveTop from Tree interface.

Make Tree.get accept Future<Path>.

Use get to implement resolveTop also in ObjectTree?.

Unify resolveTop and get in RemoteTree?.

Another minor step.

More minor changes in tree operations.

Minor organizational changes.

In RemoteTree? first fetch info for root.

Reworking resolving.

Minor changes.

Make ListAccess? return proxy iterators (instead of creating temporary collection).

Let AccessInterface? return Iterable<Param>.

Improve resolving.

More improvements.

First working completion in ManagedConsole?.

Rename resolve to resolveTop.

This reflects the actuall functionality.

Change semantic of tryResolve and tryResolveAndGet.

File size: 8.0 KB
Line 
1package com.framsticks.parsers;
2
3import java.io.BufferedReader;
4import java.io.IOException;
5import java.io.InputStream;
6import java.io.InputStreamReader;
7import java.text.ParseException;
8import java.util.ArrayList;
9import java.util.List;
10
11import com.framsticks.model.Model;
12import com.framsticks.model.f0.Schema;
13
14import static com.framsticks.params.SimpleAbstractAccess.*;
15
16import com.framsticks.params.Flags;
17import com.framsticks.params.Param;
18import com.framsticks.params.PrimitiveParam;
19import com.framsticks.util.FramsticksException;
20import com.framsticks.util.io.Encoding;
21import com.framsticks.util.lang.Containers;
22import com.framsticks.util.lang.Pair;
23import com.framsticks.util.lang.Strings;
24import org.apache.log4j.Logger;
25
26import com.framsticks.params.FramsClass;
27import com.framsticks.params.AccessInterface;
28
29/**
30 * The class Parser is used to parse genotype encoded in f0 representation.
31 */
32public class F0Parser {
33
34        private final static Logger log = Logger.getLogger(F0Parser.class);
35
36        /** The schema proper for f0 representation. */
37        protected final Schema schema;
38        protected final InputStream is;
39        protected final List<AccessInterface> result = new ArrayList<AccessInterface>();
40        int lineNumber = 0;
41
42        public F0Parser(Schema schema, InputStream is) {
43                assert schema != null;
44                assert is != null;
45                this.schema = schema;
46                this.is = is;
47        }
48
49        protected AccessInterface processLine(String line) {
50                try {
51
52                        Pair<String, String> p = Strings.splitIntoPair(line, ':', "");
53                        String classId = p.first.trim();
54                        FramsClass framsClass = schema.getFramsClass(classId);
55                        if (framsClass == null) {
56                                throw new Exception("unknown class id: " + classId);
57                        }
58                        AccessInterface access = schema.getRegistry().createAccess(classId, framsClass);
59                        access.select(access.createAccessee());
60                        for (Exception e : loadFromLine(access, p.second)) {
61                                warn(lineNumber, "however entry was added", e);
62                        }
63                        return access;
64                } catch (Exception e) {
65                        warn(lineNumber, "entry was not added", e);
66                }
67                return null;
68        }
69
70        /**
71         * Parses the stream with genotype in f0 representation. The correctness of
72         * genotype is checked. IO and syntax exceptions interrupts parsing and no
73         * result is returned. Other exceptions, connected with schema validation
74         * cause that certain object or it's parameter is ignored (appropriate
75         * communicate informs user about it). Inappropriate values in numeric
76         * fields (bigger than maximum or smaller than minimum values) are
77         * communicated by warnings and set to minimum / maximum value.
78         *
79         * @return the list
80         * @throws IOException
81         *             Signals that an I/O exception has occurred.
82         * @throws ParseException
83         *             the parse exception
84         */
85        public List<AccessInterface> parse() {
86
87                try (InputStreamReader reader = new InputStreamReader(is, Encoding.getDefaultCharset())) {
88                        BufferedReader br = new BufferedReader(reader);
89                        while (br.ready()) {
90                                ++lineNumber;
91                                String line = br.readLine();
92                                line = (line == null ? "" : line.trim());
93                                if (lineNumber == 1) {
94                                        if (!"//0".equals(line)) {
95                                                log.warn("stream should begin with \"//0\" in the first line");
96                                        } else {
97                                                continue;
98                                        }
99                                }
100                                if (line.equals("")) {
101                                        continue;
102                                }
103                                if (line.startsWith("#")) {
104                                        continue;
105                                }
106                                AccessInterface access = processLine(line);
107                                if (access != null) {
108                                        result.add(access);
109                                }
110                        }
111
112                        /** If no 'm' (Model) line was found, than simulate it on the beginning of the result.*/
113                        if (result.isEmpty() || !(result.get(0) instanceof Model)) {
114                                result.add(0, processLine("m:"));
115                        }
116                } catch (IOException e) {
117                        throw new FramsticksException().msg("failed to parse f0").arg("parser", this).arg("schema", schema).cause(e);
118                }
119
120                return result;
121        }
122
123        private static void warn(int lineNumber, String message, Exception e) {
124                log.warn("in line " + lineNumber + " the following error occurred (" + message + "): " + e);
125        }
126
127        /** Breaks string into entries.*/
128        public List<Entry> breakIntoEntries(String parameters) throws Exception {
129                // tokenize
130                boolean inQuotes = false;
131                char previousChar = ',';
132                List<Entry> result = new ArrayList<Entry>();
133                StringBuilder stringBuilder = new StringBuilder();
134                String key = null;
135                if (parameters.trim().length() > 0) {
136                        for (char currentChar : parameters.toCharArray()) {
137                                if (!inQuotes && (currentChar == '=') && (key == null)) {
138                                        key = stringBuilder.toString().trim();
139                                        stringBuilder = new StringBuilder();
140                                } else if (!inQuotes && currentChar == ',') {
141                                        if (previousChar == ',') {
142                                                result.add(new Entry(key, null));
143                                        } else {
144                                                result.add(new Entry(key, stringBuilder.toString().trim()));
145                                        }
146                                        stringBuilder = new StringBuilder();
147                                        key = null;
148                                } else if (currentChar == '"') {
149                                        if (previousChar == '\\') {
150                                                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
151                                                stringBuilder.append(currentChar);
152                                        } else {
153                                                inQuotes = !inQuotes;
154                                        }
155                                } else {
156                                        stringBuilder.append(currentChar);
157                                }
158
159                                previousChar = currentChar;
160                        }
161
162                        result.add(new Entry(key, stringBuilder.toString().trim()));
163
164                        if (inQuotes) {
165                                throw new Exception("Double quotes expected while end of line met");
166                        }
167                }
168                return result;
169        }
170
171        public List<Exception> loadFromLine(AccessInterface access, String parameters) throws Exception {
172
173                List<Entry> entries = breakIntoEntries(parameters);
174
175                List<Exception> exceptions = new ArrayList<Exception>();
176
177                List<Param> paramsL = new ArrayList<>();
178
179                for (Param param : access.getParams()) {
180                        paramsL.add(param);
181                }
182
183                Param[] params = paramsL.toArray(new Param[] {null});
184                if (params.length == 0) {
185                        return exceptions;
186                }
187                for (PrimitiveParam<?> p : Containers.filterInstanceof(paramsL, PrimitiveParam.class)) {
188                        Object def = p.getDef(Object.class);
189                        if (def != null) {
190                                access.set(p, def);
191                        }
192                }
193
194                int number = -1;
195                Integer nextParamNumber = 0;
196                for (Entry pair : entries) {
197                        ++number;
198                        try {
199                                Param currentParam;
200                                if (pair.key != null) {
201                                        currentParam = access.getParam(pair.key);
202                                        if (currentParam == null) {
203                                                nextParamNumber = null;
204                                                throw new Exception("no parameter with such id: " + pair.key);
205                                        }
206                                } else {
207                                        if (nextParamNumber == null || ((params[nextParamNumber].getFlags() & Flags.CANOMITNAME) == 0)) {
208                                                nextParamNumber = null;
209                                                throw new Exception(
210                                                                "parameter with offset: "
211                                                                                + number
212                                                                                + " is not set, "
213                                                                                + "because it's definition or definition of the previous param "
214                                                                                + "does not contain flag, which allows to skip the name (flag 1024)");
215                                        }
216                                        currentParam = params[nextParamNumber];
217                                }
218                                if (currentParam != null) {
219                                        if (pair.value != null) {
220                                                PrimitiveParam<?> vp = (PrimitiveParam<?>) currentParam;
221                                                int setFlag = access.set(vp, pair.value);
222                                                if ((setFlag & Flags.PSET_HITMIN) != 0) {
223                                                        exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMIN));
224                                                }
225
226                                                if ((setFlag & Flags.PSET_HITMAX) != 0) {
227                                                        exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMAX));
228                                                }
229
230                                                if ((setFlag & Flags.PSET_RONLY) != 0) {
231                                                        throw (new Exception("tried to set a read-only attribute \""
232                                                                + currentParam.getId()
233                                                                + "\" in class \"" + access.getId() + "\""));
234                                                }
235                                        }
236                                        nextParamNumber = null;
237                                        for (int j = params.length - 1; j > 0; --j) {
238                                                if (params[j - 1] == currentParam) {
239                                                        nextParamNumber = j;
240                                                }
241                                        }
242                                }
243
244                        } catch (Exception e) {
245                                exceptions.add(e);
246                        }
247                }
248                return exceptions;
249        }
250
251        private static Exception createBoundaryHitException(AccessInterface access, PrimitiveParam<?> param, String value, int flag) {
252                boolean minimum = (flag & Flags.PSET_HITMIN) != 0;
253                String boundary = (minimum ? param.getMin(Object.class) : param.getMax(Object.class)).toString();
254                String name =  (minimum ? "minimum" : "maximum");
255                return new Exception("Tried to set attribute \""
256                                + param.getId()
257                                + "\" in class \""
258                                + access.getId()
259                                + "\" to value which exceeds " + name + " ("
260                                + value
261                                + "), truncated to: "
262                                + boundary);
263        }
264}
Note: See TracBrowser for help on using the repository browser.