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

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

HIGHLIGHTS:

CHANGELOG:
Make ProcedureParam? hold only ValueParams?.

Use id instead of names when naming gui components internally.

Basic procedure calling in GUI.

The actual procedure call is currently only backed
by the ObjectInstance?.

Add UnimplementedException?.

Improve naming of various gui elements.

Allow easy navigating in FEST Swing testing.

Add optional explicit order attribute to FramsClassAnnotation?.

That's because java reflection does return declared members
in any specific order. That ordering is needed only for
classes that have no representation in framsticks and need
a deterministic ordering of params.

Add ControlOwner? interface.

Add test for procedure calling in Browser.

First version of ParamAnnotation? for procedures.

Development of ProcedureParam?.

Add draft version of ProcedureParam? implementation in ReflectionAccess?.

Allow viewing FramsClasses? in gui Browser.

Extract ResourceBuilder? from ModelBuilder?.

Remove internalId from Param.

It was currently completely not utilised. Whether it is still needed
after introduction of ParamAnnotation? is arguable.

Add remaining param attributes to ParamAnnotation?.

Change AutoBuilder? semantics.

AutoBuilder? returns list of objects that are to be appended
with methods @AutoAppendAnnotation?.

This allows to omit explicit addition of ModelPackage? to instance
if the instance uses ModelBuilder? (registration of ModelPackage? comes
from schema).

Fix params ordering problem in auto created FramsClasses?.

Improve ObjectInstance?.

Several fixes to ModelBuilder?.

Improve test for ObjectInstance? in Browser.

Make initialization of robot static.

With robot recreated for second browser test, the test hanged
deep in AWT.

Add base convenience base test for Browser tests.

More tests to ObjectInstance?.

Rename Dispatcher.invokeLater() to dispatch().

Add assertDispatch.

It allows assertions in other threads, than TestNGInvoker.
Assertions are gathered after each method invocation and rethrown.

Use timeOut annotation attribute for tests involving some waiting.

Remove firstTask method (merge with joinableStart).

Clean up leftovers.

Remove unused FavouritesXMLFactory (the reading part is already
completely done with generic XmlLoader?, and writing part will be done
based on the same approach if needed).
Move UserFavourite? to the com.framsticks.gui.configuration package.

Remove GenotypeBrowser? as to specific.

This functionality will be available in ObjectInstance?.

Add interface ParamsPackage?.

Package containing registration of Java classes meant to use with
ReflectionAccess? may be in Instance using configuration.

Minor changes.

Make Group immutable.

Add AutoBuilder? interface extending Builder - only those would
be used to automatically build from XML.

Fix groups in FramsClass?.

Minor naming cleanup in Registry.

Add ModelComponent? interface.

All class creating the Model are implementing that interface.

Extract Model.build into ModelBuilder?.

ModelBuilder? will be compatible with other builders
and allow using it from configuration.

Fix NeuroConnection?.

Add synchronous get operation for dispatchers.

Rename JoinableMonitor? to Monitor.

Add ObjectInstance?.

This class is mainly for demonstration
and testing purposes.

Improve FramsServer? runner.

  • improve ExternalProcess? runner,
  • runner can kill the server but also react properly, when the server exists on it's own,
  • set default path to search for framsticks server installation,
  • add LoggingOutputListener?.
File size: 7.9 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.Collection;
10import java.util.List;
11
12import com.framsticks.model.Model;
13import com.framsticks.model.f0.Schema;
14
15import static com.framsticks.params.SimpleAbstractAccess.*;
16
17import com.framsticks.params.Flags;
18import com.framsticks.params.Param;
19import com.framsticks.params.PrimitiveParam;
20import com.framsticks.util.FramsticksException;
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, "UTF-8")) {
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                Collection<Param> paramsC = access.getParams();
178                Param[] params = paramsC.toArray(new Param[] {null});
179                if (params.length == 0) {
180                        return exceptions;
181                }
182                for (PrimitiveParam<?> p : Containers.filterInstanceof(paramsC, PrimitiveParam.class)) {
183                        Object def = p.getDef(Object.class);
184                        if (def != null) {
185                                access.set(p, def);
186                        }
187                }
188
189                int number = -1;
190                Integer nextParamNumber = 0;
191                for (Entry pair : entries) {
192                        ++number;
193                        try {
194                                Param currentParam;
195                                if (pair.key != null) {
196                                        currentParam = access.getParam(pair.key);
197                                        if (currentParam == null) {
198                                                nextParamNumber = null;
199                                                throw new Exception("no parameter with such id: " + pair.key);
200                                        }
201                                } else {
202                                        if (nextParamNumber == null || ((params[nextParamNumber].getFlags() & Flags.CANOMITNAME) == 0)) {
203                                                nextParamNumber = null;
204                                                throw new Exception(
205                                                                "parameter with offset: "
206                                                                                + number
207                                                                                + " is not set, "
208                                                                                + "because it's definition or definition of the previous param "
209                                                                                + "does not contain flag, which allows to skip the name (flag 1024)");
210                                        }
211                                        currentParam = params[nextParamNumber];
212                                }
213                                if (currentParam != null) {
214                                        if (pair.value != null) {
215                                                PrimitiveParam<?> vp = (PrimitiveParam<?>) currentParam;
216                                                int setFlag = access.set(vp, pair.value);
217                                                if ((setFlag & Flags.PSET_HITMIN) != 0) {
218                                                        exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMIN));
219                                                }
220
221                                                if ((setFlag & Flags.PSET_HITMAX) != 0) {
222                                                        exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMAX));
223                                                }
224
225                                                if ((setFlag & Flags.PSET_RONLY) != 0) {
226                                                        throw (new Exception("tried to set a read-only attribute \""
227                                                                + currentParam.getId()
228                                                                + "\" in class \"" + access.getId() + "\""));
229                                                }
230                                        }
231                                        nextParamNumber = null;
232                                        for (int j = params.length - 1; j > 0; --j) {
233                                                if (params[j - 1] == currentParam) {
234                                                        nextParamNumber = j;
235                                                }
236                                        }
237                                }
238
239                        } catch (Exception e) {
240                                exceptions.add(e);
241                        }
242                }
243                return exceptions;
244        }
245
246        private static Exception createBoundaryHitException(AccessInterface access, PrimitiveParam<?> param, String value, int flag) {
247                boolean minimum = (flag & Flags.PSET_HITMIN) != 0;
248                String boundary = (minimum ? param.getMin(Object.class) : param.getMax(Object.class)).toString();
249                String name =  (minimum ? "minimum" : "maximum");
250                return new Exception("Tried to set attribute \""
251                                + param.getId()
252                                + "\" in class \""
253                                + access.getId()
254                                + "\" to value which exceeds " + name + " ("
255                                + value
256                                + "), truncated to: "
257                                + boundary);
258        }
259}
Note: See TracBrowser for help on using the repository browser.