Home | History | Annotate | Download | only in resolver
      1 /**
      2  * Copyright (c) 2008, http://www.snakeyaml.org
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package org.yaml.snakeyaml.resolver;
     17 
     18 import java.util.ArrayList;
     19 import java.util.HashMap;
     20 import java.util.List;
     21 import java.util.Map;
     22 import java.util.regex.Pattern;
     23 
     24 import org.yaml.snakeyaml.nodes.NodeId;
     25 import org.yaml.snakeyaml.nodes.Tag;
     26 
     27 /**
     28  * Resolver tries to detect a type by content (when the tag is implicit)
     29  */
     30 public class Resolver {
     31     public static final Pattern BOOL = Pattern
     32             .compile("^(?:yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)$");
     33 
     34     /**
     35      * The regular expression is taken from the 1.2 specification but '_'s are
     36      * added to keep backwards compatibility
     37      */
     38     public static final Pattern FLOAT = Pattern
     39             .compile("^([-+]?(\\.[0-9]+|[0-9_]+(\\.[0-9_]*)?)([eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");
     40     public static final Pattern INT = Pattern
     41             .compile("^(?:[-+]?0b[0-1_]+|[-+]?0[0-7_]+|[-+]?(?:0|[1-9][0-9_]*)|[-+]?0x[0-9a-fA-F_]+|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$");
     42     public static final Pattern MERGE = Pattern.compile("^(?:<<)$");
     43     public static final Pattern NULL = Pattern.compile("^(?:~|null|Null|NULL| )$");
     44     public static final Pattern EMPTY = Pattern.compile("^$");
     45     public static final Pattern TIMESTAMP = Pattern
     46             .compile("^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?(?:[Tt]|[ \t]+)[0-9][0-9]?:[0-9][0-9]:[0-9][0-9](?:\\.[0-9]*)?(?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$");
     47     public static final Pattern VALUE = Pattern.compile("^(?:=)$");
     48     public static final Pattern YAML = Pattern.compile("^(?:!|&|\\*)$");
     49 
     50     protected Map<Character, List<ResolverTuple>> yamlImplicitResolvers = new HashMap<Character, List<ResolverTuple>>();
     51 
     52     protected void addImplicitResolvers() {
     53         addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
     54         /*
     55          * INT must be before FLOAT because the regular expression for FLOAT
     56          * matches INT (see issue 130)
     57          * http://code.google.com/p/snakeyaml/issues/detail?id=130
     58          */
     59         addImplicitResolver(Tag.INT, INT, "-+0123456789");
     60         addImplicitResolver(Tag.FLOAT, FLOAT, "-+0123456789.");
     61         addImplicitResolver(Tag.MERGE, MERGE, "<");
     62         addImplicitResolver(Tag.NULL, NULL, "~nN\0");
     63         addImplicitResolver(Tag.NULL, EMPTY, null);
     64         addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789");
     65         // The following implicit resolver is only for documentation
     66         // purposes.
     67         // It cannot work
     68         // because plain scalars cannot start with '!', '&', or '*'.
     69         addImplicitResolver(Tag.YAML, YAML, "!&*");
     70     }
     71 
     72     public Resolver() {
     73         addImplicitResolvers();
     74     }
     75 
     76     public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
     77         if (first == null) {
     78             List<ResolverTuple> curr = yamlImplicitResolvers.get(null);
     79             if (curr == null) {
     80                 curr = new ArrayList<ResolverTuple>();
     81                 yamlImplicitResolvers.put(null, curr);
     82             }
     83             curr.add(new ResolverTuple(tag, regexp));
     84         } else {
     85             char[] chrs = first.toCharArray();
     86             for (int i = 0, j = chrs.length; i < j; i++) {
     87                 Character theC = Character.valueOf(chrs[i]);
     88                 if (theC == 0) {
     89                     // special case: for null
     90                     theC = null;
     91                 }
     92                 List<ResolverTuple> curr = yamlImplicitResolvers.get(theC);
     93                 if (curr == null) {
     94                     curr = new ArrayList<ResolverTuple>();
     95                     yamlImplicitResolvers.put(theC, curr);
     96                 }
     97                 curr.add(new ResolverTuple(tag, regexp));
     98             }
     99         }
    100     }
    101 
    102     public Tag resolve(NodeId kind, String value, boolean implicit) {
    103         if (kind == NodeId.scalar && implicit) {
    104             List<ResolverTuple> resolvers = null;
    105             if (value.length() == 0) {
    106                 resolvers = yamlImplicitResolvers.get('\0');
    107             } else {
    108                 resolvers = yamlImplicitResolvers.get(value.charAt(0));
    109             }
    110             if (resolvers != null) {
    111                 for (ResolverTuple v : resolvers) {
    112                     Tag tag = v.getTag();
    113                     Pattern regexp = v.getRegexp();
    114                     if (regexp.matcher(value).matches()) {
    115                         return tag;
    116                     }
    117                 }
    118             }
    119             if (yamlImplicitResolvers.containsKey(null)) {
    120                 for (ResolverTuple v : yamlImplicitResolvers.get(null)) {
    121                     Tag tag = v.getTag();
    122                     Pattern regexp = v.getRegexp();
    123                     if (regexp.matcher(value).matches()) {
    124                         return tag;
    125                     }
    126                 }
    127             }
    128         }
    129         switch (kind) {
    130         case scalar:
    131             return Tag.STR;
    132         case sequence:
    133             return Tag.SEQ;
    134         default:
    135             return Tag.MAP;
    136         }
    137     }
    138 }