Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.expressionevaluator / org.gvsig.expressionevaluator.lib / org.gvsig.expressionevaluator.lib.impl / src / main / java / org / gvsig / expressionevaluator / impl / DefaultStatement.java @ 44408

History | View | Annotate | Download (16.3 KB)

1 44139 jjdelcerro
package org.gvsig.expressionevaluator.impl;
2
3
import java.util.ArrayList;
4
import java.util.List;
5 44379 jjdelcerro
import java.util.Objects;
6 44139 jjdelcerro
import org.apache.commons.lang3.ArrayUtils;
7
import org.apache.commons.lang3.StringUtils;
8
import org.gvsig.expressionevaluator.Code;
9
import org.gvsig.expressionevaluator.Code.Caller;
10
import org.gvsig.expressionevaluator.Codes;
11 44262 jjdelcerro
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_LIST;
12 44139 jjdelcerro
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
13
import org.gvsig.expressionevaluator.LexicalAnalyzer.Token;
14
import org.gvsig.expressionevaluator.Statement;
15
import org.gvsig.expressionevaluator.Statement.CompoundRule;
16
import org.gvsig.expressionevaluator.Statement.ConditionalRule;
17
import org.gvsig.expressionevaluator.Statement.Rule;
18
import org.gvsig.expressionevaluator.Statement.StatementContext;
19
import org.gvsig.expressionevaluator.impl.function.programming.CodeBlockFunction;
20
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseCodes;
21
22
/**
23
 *
24
 * @author jjdelcerro
25
 */
26
public class DefaultStatement implements Statement {
27
28
    private final List<Rule> rules;
29
    private final String name;
30 44384 jjdelcerro
    private StatementBuilder stmtBuilder;
31
//    private String codeId;
32
//    private ArgsBuilder argsBuilder;
33 44139 jjdelcerro
34
    public interface RepeatRule extends CompoundRule {
35
36
        public String getClassifier();
37
    }
38
39 44144 jjdelcerro
    public class RuleRequireAnyToken implements Rule {
40 44139 jjdelcerro
41
        private final String[] required_token;
42
43 44144 jjdelcerro
        public RuleRequireAnyToken(String... required_token) {
44 44139 jjdelcerro
            this.required_token = required_token;
45
        }
46
47 44379 jjdelcerro
        @Override
48 44139 jjdelcerro
        public void parse(StatementContext context) {
49
            Token token = context.look_token();
50
            if (!token.is(this.required_token)) {
51
                throw new ExpressionSyntaxException(
52
                        I18N.A_XTokenX_was_expected_and_XliteralX_was_found(
53 44384 jjdelcerro
                                StringUtils.join(this.required_token,", "),
54 44139 jjdelcerro
                                token.getLiteral()
55
                        ),
56
                        context.getLexicalAnalyzer()
57
                );
58
            }
59
            context.next_token();
60
        }
61
62
        private boolean isApplicable(StatementContext context) {
63
            Token token = context.look_token();
64
            return token.is(this.required_token);
65
        }
66
67
        @Override
68
        public String toString() {
69
            return "require_token(" + StringUtils.join(this.required_token) + ")";
70
        }
71
72
    }
73
74
    public class RuleRequireIdentifier implements Rule {
75
76
        private final String id;
77
78
        public RuleRequireIdentifier(String id) {
79
            this.id = id;
80
        }
81
82 44379 jjdelcerro
        @Override
83 44139 jjdelcerro
        public void parse(StatementContext context) {
84
            Token token = context.look_token();
85
            if (token.getType() != Token.IDENTIFIER) {
86
                throw new ExpressionSyntaxException(
87
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
88
                        context.getLexicalAnalyzer()
89
                );
90
            }
91
            String identifier = (String) token.getLiteral();
92
            Code code = context.getCodeBuilder().constant(identifier);
93
            context.setCode(id, code);
94
            context.next_token();
95
        }
96
97
        @Override
98
        public String toString() {
99
            return "require_identifier('" + this.id + "')";
100
        }
101
    }
102
103
    public class RuleRequireExpression implements Rule {
104
105
        private final String id;
106
107
        public RuleRequireExpression(String id) {
108
            this.id = id;
109
        }
110
111 44379 jjdelcerro
        @Override
112 44139 jjdelcerro
        public void parse(StatementContext context) {
113
            Code code = context.parse_expression();
114
            if (code == null) {
115
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
116
            }
117
            context.setCode(id, code);
118
        }
119
120
        @Override
121
        public String toString() {
122
            return "require_expression('" + this.id + "')";
123
        }
124
    }
125
126 44379 jjdelcerro
127
    public class RuleSetExpression implements Rule {
128
129
        private final String id;
130
        private final Object value;
131
132
        public RuleSetExpression(String id, Object value) {
133
            this.id = id;
134
            this.value = value;
135
        }
136
137
        @Override
138
        public void parse(StatementContext context) {
139
            if( this.value instanceof Code ) {
140
                context.setCode(id, (Code) this.value);
141
            } else {
142
                context.setCode(id, context.getCodeBuilder().constant(value));
143
            }
144
        }
145
146
        @Override
147
        public String toString() {
148
            return "set_expression('" + this.id + "', "+Objects.toString(value)+")";
149
        }
150
    }
151
152 44139 jjdelcerro
    public class RuleRequiereExpressions implements Rule {
153
154
        private final String id;
155
        private final String separator;
156
157
        public RuleRequiereExpressions(String id, String separator) {
158
            this.id = id;
159
            this.separator = separator;
160
        }
161
162 44379 jjdelcerro
        @Override
163 44139 jjdelcerro
        public void parse(StatementContext context) {
164
            Codes codes = context.parse_expressions(this.separator);
165
            if (codes == null) {
166
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
167
            }
168 44379 jjdelcerro
            Code code;
169
            if( codes.size()==1 ) {
170
                code = codes.get(0);
171
            } else {
172
                code = context.getCodeBuilder().function(CodeBlockFunction.NAME, codes);
173
            }
174 44139 jjdelcerro
            context.setCode(id, code);
175
        }
176
177
        @Override
178
        public String toString() {
179
            return "require_expressions('" + this.id + "', '" + this.separator + "')";
180
        }
181
    }
182
183 44144 jjdelcerro
    public class RuleOptionalAnyToken implements ConditionalRule {
184 44139 jjdelcerro
185
        private final String[] optional_token;
186
        private final List<Rule> onTrueRules;
187
        private final List<Rule> onFalseRules;
188
189 44144 jjdelcerro
        public RuleOptionalAnyToken(String... optional_token) {
190 44139 jjdelcerro
            this.optional_token = optional_token;
191
            this.onTrueRules = new ArrayList<>();
192
            this.onFalseRules = new ArrayList<>();
193
        }
194
195 44379 jjdelcerro
        @Override
196 44139 jjdelcerro
        public void parse(StatementContext context) {
197
            Token token = context.look_token();
198
            if (token.is(this.optional_token)) {
199
                context.next_token();
200
                for (Rule rule : this.onTrueRules) {
201
                    rule.parse(context);
202
                }
203
            } else {
204
                for (Rule rule : this.onFalseRules) {
205
                    rule.parse(context);
206
                }
207
            }
208
        }
209
210 44379 jjdelcerro
        @Override
211 44144 jjdelcerro
        public RuleOptionalAnyToken addRuleOnTrue(Rule rule) {
212 44139 jjdelcerro
            this.onTrueRules.add(rule);
213
            return this;
214
        }
215
216 44379 jjdelcerro
        @Override
217 44144 jjdelcerro
        public RuleOptionalAnyToken addRuleOnFalse(Rule rule) {
218 44139 jjdelcerro
            this.onFalseRules.add(rule);
219
            return this;
220
        }
221
222
        @Override
223
        public String toString() {
224
            return "optional_token(" + StringUtils.join(this.optional_token) + ") rules:" + StringUtils.join(onTrueRules, ",");
225
        }
226
    }
227
228 44144 jjdelcerro
    public class RuleRepeatUntilAnyTokens implements RepeatRule {
229 44139 jjdelcerro
230
        private final String[] exit_tokens;
231
        private final List<Rule> rules;
232
        private int counter;
233
234 44144 jjdelcerro
        public RuleRepeatUntilAnyTokens(String[] exit_tokens) {
235 44139 jjdelcerro
            this.exit_tokens = exit_tokens;
236
            this.rules = new ArrayList<>();
237
        }
238
239 44379 jjdelcerro
        @Override
240 44139 jjdelcerro
        public void parse(StatementContext context) {
241
            String save = context.getCodeClassifier();
242
            try {
243
                this.counter = 1;
244
                while (true) {
245
                    Token token = context.look_token();
246
                    if (token.is(this.exit_tokens)) {
247
                        break;
248
                    }
249
                    context.setCodeClassifier(String.valueOf(counter).trim());
250
                    for (Rule rule : rules) {
251
                        rule.parse(context);
252
                    }
253
                    this.counter = this.counter + 1;
254
                }
255
            } finally {
256
                context.setCodeClassifier(save);
257
            }
258
        }
259
260 44379 jjdelcerro
        @Override
261 44144 jjdelcerro
        public RuleRepeatUntilAnyTokens addRule(Rule rule) {
262 44139 jjdelcerro
            this.rules.add(rule);
263
            return this;
264
        }
265
266
        @Override
267
        public String getClassifier() {
268
            String s = String.valueOf(counter).trim();
269
            return s;
270
        }
271
272
        @Override
273
        public String toString() {
274
            return "repeat_until_tokens('" + ArrayUtils.toString(this.exit_tokens) + "') rules:" + StringUtils.join(rules, ",");
275
        }
276
    }
277
278
    public class RuleOptionalIdentifiers implements Rule {
279
280
        private final String id;
281
        private final String separator;
282
283
        public RuleOptionalIdentifiers(String id, String separator) {
284
            this.id = id;
285
            this.separator = separator;
286
        }
287
288 44379 jjdelcerro
        @Override
289 44139 jjdelcerro
        public void parse(StatementContext context) {
290
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
291
            Token token = context.look_token();
292
            while (token.getType() == Token.IDENTIFIER) {
293
                String identifier = (String) token.getLiteral();
294 44384 jjdelcerro
                if( context.isReservedWord(identifier) ) {
295
                    break;
296
                }
297 44139 jjdelcerro
                Code code = context.getCodeBuilder().constant(identifier);
298
                args.add(code);
299
                context.next_token();
300
                token = context.look_token();
301
                if (!token.is(this.separator)) {
302
                    break;
303
                }
304
                context.next_token();
305
                token = context.look_token();
306
            }
307
            Code code = null;
308
            if (args.size() != 0) {
309 44262 jjdelcerro
                code = context.getCodeBuilder().function(FUNCTION_LIST, args);
310 44139 jjdelcerro
            }
311
            context.setCode(id, code);
312
        }
313
314
        @Override
315
        public String toString() {
316
            return "optional_identifiers('" + id + "', '" + this.separator + "')";
317
        }
318
    }
319
320 44384 jjdelcerro
    public static class ArgsBuilderFromNames implements ArgsBuilder {
321 44139 jjdelcerro
322
        private final String[] argNames;
323
324 44384 jjdelcerro
        public ArgsBuilderFromNames(String... argNames) {
325 44139 jjdelcerro
            this.argNames = argNames;
326
        }
327
328 44379 jjdelcerro
        @Override
329 44139 jjdelcerro
        public Codes build(StatementContext context) {
330
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
331
            for (String argName : argNames) {
332
                if (argName.contains("#")) {
333
                    int n = 1;
334
                    while (true) {
335
                        String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
336
                        Code code = context.getCode(argNameX);
337
                        if (code == null) {
338
                            break;
339
                        }
340
                        args.add(code);
341
                        n++;
342
                    }
343
                } else {
344
                    Code code = context.getCode(argName);
345 44384 jjdelcerro
                    if( code != null) {
346
                        args.add(code);
347
                    }
348 44139 jjdelcerro
                }
349
            }
350
            return args;
351
        }
352
    }
353
354 44384 jjdelcerro
    public static class ArgsBuilderExpand extends ArgsBuilderFromNames {
355 44139 jjdelcerro
356 44384 jjdelcerro
        public ArgsBuilderExpand(String... argNames) {
357 44139 jjdelcerro
            super(argNames);
358
        }
359
360 44379 jjdelcerro
        @Override
361 44139 jjdelcerro
        public Codes build(StatementContext context) {
362
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
363
364
            Codes base_args = super.build(context);
365
            for (Code arg : base_args) {
366
                if( arg.code() == Code.CALLER &&
367
                    ((Caller)arg).name().equals(CodeBlockFunction.NAME) ) {
368 44198 jjdelcerro
                    Codes block_args = ((Caller)arg).parameters();
369 44139 jjdelcerro
                    for (Code block_arg : block_args) {
370
                        args.add(block_arg);
371
                    }
372
                } else {
373
                    args.add(arg);
374
                }
375
            }
376
            return args;
377
        }
378
    }
379
380 44384 jjdelcerro
    public static class StatementBuilderBase implements StatementBuilder {
381
        protected ArgsBuilder argsBuilder;
382
        protected String codeID;
383
384
        public StatementBuilderBase(String codeID, ArgsBuilder argsBuilder) {
385
            this.codeID = codeID;
386
            this.argsBuilder = argsBuilder;
387
        }
388
389
        @Override
390
        public String getCodeID() {
391
            return this.codeID;
392
        }
393
394
        @Override
395
        public ArgsBuilder getArgsBuilder() {
396
            return this.argsBuilder;
397
        }
398
399
        @Override
400
        public Code build(StatementContext context) {
401
            Codes args = this.getArgsBuilder().build(context);
402
            Code code = null;
403
            if (this.getCodeID() == null) {
404
                code = args.get(0);
405
            } else {
406
                if (args.size() == 0) {
407
                    code = context.getCodeBuilder().function(this.getCodeID(), null);
408
                } else {
409
                    // Si es un bloque dentro de otro, dejamos solo uno.
410
                    if( args.size()==1 &&
411
                        StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,this.getCodeID()) ) {
412
                        Code code0 = args.get(0);
413
                        if( code0.code() == Code.CALLER &&
414
                                StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,((Caller)code0).name())
415
                                ) {
416
                            code = code0;
417
                        }
418
                    }
419
                    if( code == null ) {
420
                        code = context.getCodeBuilder().function(this.getCodeID(), args);
421
                    }
422
                }
423
            }
424
            return code;
425
        }
426
    }
427
428 44139 jjdelcerro
    public DefaultStatement(String name) {
429
        this.rules = new ArrayList<>();
430 44384 jjdelcerro
        this.stmtBuilder = null;
431 44139 jjdelcerro
        this.name = name;
432
    }
433
434 44379 jjdelcerro
    @Override
435 44139 jjdelcerro
    public String getName() {
436
        return name;
437
    }
438
439
    @Override
440 44144 jjdelcerro
    public Rule require_any_token(String... token) {
441
        return new RuleRequireAnyToken(token);
442 44139 jjdelcerro
    }
443
444
    @Override
445
    public Rule require_identifier(String id) {
446
        return new RuleRequireIdentifier(id);
447
    }
448
449
    @Override
450 44379 jjdelcerro
    public Rule set_expression(String id, Object value) {
451
        return new RuleSetExpression(id, value);
452
    }
453
454
    @Override
455 44139 jjdelcerro
    public Rule require_expression(String id) {
456
        return new RuleRequireExpression(id);
457
    }
458
459
    @Override
460
    public Rule require_expressions(String id, String separator) {
461
        return new RuleRequiereExpressions(id, separator);
462
    }
463
464
    @Override
465 44144 jjdelcerro
    public ConditionalRule optional_any_token(String... id) {
466
        return new RuleOptionalAnyToken(id);
467 44139 jjdelcerro
    }
468
469
    @Override
470
    public Rule optional_identifiers(String id, String separator) {
471
        return new RuleOptionalIdentifiers(id, separator);
472
    }
473
474
    @Override
475 44144 jjdelcerro
    public CompoundRule repeat_until_any_tokens(String... tokens) {
476
        return new RuleRepeatUntilAnyTokens(tokens);
477 44139 jjdelcerro
    }
478
479
    @Override
480
    public Statement addRule(Rule rule) {
481
        this.rules.add(rule);
482
        return this;
483
    }
484
485
    @Override
486
    public boolean isApplicable(StatementContext context) {
487
        if (this.rules.isEmpty()) {
488
            return false;
489
        }
490
        Rule rule = this.rules.get(0);
491 44144 jjdelcerro
        if (!(rule instanceof RuleRequireAnyToken)) {
492 44139 jjdelcerro
            return false;
493
        }
494 44144 jjdelcerro
        return ((RuleRequireAnyToken) rule).isApplicable(context);
495 44139 jjdelcerro
    }
496
497
    @Override
498
    public ArgsBuilder args_names(String... args) {
499
        ArgsBuilder x = new ArgsBuilderFromNames(args);
500
        return x;
501
    }
502
503
    @Override
504
    public ArgsBuilder args_expand(String... args) {
505
        ArgsBuilder x = new ArgsBuilderExpand(args);
506
        return x;
507
    }
508
509
    @Override
510 44384 jjdelcerro
    public void code(final String id, final ArgsBuilder argsBuilder) {
511
        this.builder(new StatementBuilderBase(id, argsBuilder));
512 44139 jjdelcerro
    }
513
514 44384 jjdelcerro
    public void builder(StatementBuilder builder) {
515
        this.stmtBuilder = builder;
516
    }
517
518 44139 jjdelcerro
    @Override
519
    public Code parse(StatementContext context) {
520 44379 jjdelcerro
//        System.err.println("start parse "+this.getName());
521 44139 jjdelcerro
        for (Rule rule : rules) {
522
            rule.parse(context);
523
        }
524 44384 jjdelcerro
        Code code = this.stmtBuilder.build(context);
525 44139 jjdelcerro
        return code;
526
    }
527
528
    @Override
529
    public String toString() {
530
        return this.getName() + " " + StringUtils.join(this.rules, ";");
531
532
    }
533
}