yang - add range statement
diff --git a/src/parser_yang.c b/src/parser_yang.c
index bc3d834..a8529da 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -229,6 +229,9 @@
         case PATTERN_KEYWORD:
             ret = yang_check_string(module, &((struct lys_restr *) node)->dsc, "description", "pattern", value, line);
             break;
+        case RANGE_KEYWORD:
+            ret = yang_check_string(module, &((struct lys_restr *) node)->dsc, "description", "range", value, line);
+            break;
         }
     }
     return ret;
@@ -288,6 +291,9 @@
         case PATTERN_KEYWORD:
             ret = yang_check_string(module, &((struct lys_restr *) node)->ref, "reference", "pattern", value, line);
             break;
+        case RANGE_KEYWORD:
+            ret = yang_check_string(module, &((struct lys_restr *) node)->ref, "reference", "range", value, line);
+            break;
         }
     }
     return ret;
@@ -529,6 +535,9 @@
     case PATTERN_KEYWORD:
         exp = "pattern";
         break;
+    case RANGE_KEYWORD:
+        exp = "range";
+        break;
     }
     if (message==ERROR_APP_TAG_KEYWORD) {
         ret = yang_check_string(module, &save->eapptag, "error_app_tag", exp, value, line);
@@ -880,12 +889,7 @@
         if (typ->type->base == LY_TYPE_BINARY) {
             if (typ->type->info.str.pat_count) {
                 LOGVAL(LYE_SPEC, typ->line, LY_VLOG_NONE, NULL, "Binary type could not include pattern statement.");
-
-                /* clean patterns */
-                for (i = 0; i < typ->type->info.str.pat_count; ++i) {
-                    lys_restr_free(module->ctx, &(typ->type->info.str.patterns[i]));
-                }
-                free(typ->type->info.str.patterns);
+                typ->type->base = base;
                 goto error;
             }
             typ->type->info.binary.length = typ->type->info.str.length;
@@ -898,7 +902,33 @@
                 LOGVAL(LYE_INARG, typ->line, LY_VLOG_NONE, NULL, typ->type->info.str.length->expr, "length");
                 goto error;
             }
+        } else {
+            LOGVAL(LYE_SPEC, typ->line, LY_VLOG_NONE, NULL, "Invalid restriction in type \"%s\".", parent->name);
+            goto error;
         }
+        break;
+    case LY_TYPE_DEC64:
+        if (typ->type->base == LY_TYPE_DEC64) {
+            if (lyp_check_length_range(typ->type->info.dec64.range->expr, typ->type)) {
+                LOGVAL(LYE_INARG, typ->line, LY_VLOG_NONE, NULL, typ->type->info.dec64.range->expr, "range");
+                goto error;
+            }
+        } else if (typ->type->base >= LY_TYPE_INT8 && typ->type->base <=LY_TYPE_UINT64) {
+            if (typ->type->info.dec64.dig) {
+                LOGVAL(LYE_SPEC, typ->line, LY_VLOG_NONE, NULL, "Numerical type could not include fraction statement.");
+                typ->type->base = base;
+                goto error;
+            }
+            typ->type->info.num.range = typ->type->info.dec64.range;
+            if (lyp_check_length_range(typ->type->info.num.range->expr, typ->type)) {
+                LOGVAL(LYE_INARG, typ->line, LY_VLOG_NONE, NULL, typ->type->info.num.range->expr, "range");
+                goto error;
+            }
+        } else {
+            LOGVAL(LYE_SPEC, typ->line, LY_VLOG_NONE, NULL, "Invalid restriction in type \"%s\".", parent->name);
+            goto error;
+        }
+        break;
     }
     return EXIT_SUCCESS;
 
@@ -995,3 +1025,28 @@
     typ->type->info.str.pat_count++;
     return &typ->type->info.str.patterns[typ->type->info.str.pat_count-1];
 }
+
+void *
+yang_read_range(struct  lys_module *module, struct yang_type *typ, char *value, int line)
+{
+    if (typ->type->base != 0 && typ->type->base != LY_TYPE_DEC64) {
+        LOGVAL(LYE_SPEC, line, LY_VLOG_NONE, NULL, "Unexpected range statement.");
+        goto error;
+    }
+    typ->type->base = LY_TYPE_DEC64;
+    if (typ->type->info.dec64.range) {
+        LOGVAL(LYE_TOOMANY, line, LY_VLOG_NONE, NULL, "range", "type");
+        goto error;
+    }
+    typ->type->info.dec64.range = calloc(1, sizeof *typ->type->info.dec64.range);
+    if (!typ->type->info.dec64.range) {
+        LOGMEM;
+        goto error;
+    }
+    typ->type->info.dec64.range->expr = lydict_insert_zc(module->ctx, value);
+    return typ->type->info.dec64.range;
+
+error:
+    free(value);
+    return NULL;
+}
diff --git a/src/parser_yang.h b/src/parser_yang.h
index af18f20..b5819df 100644
--- a/src/parser_yang.h
+++ b/src/parser_yang.h
@@ -186,4 +186,6 @@
 
 void *yang_read_pattern(struct lys_module *module, struct yang_type *typ, char *value, int line);
 
+void *yang_read_range(struct  lys_module *module, struct yang_type *typ, char *value, int line);
+
 #endif /* LY_PARSER_YANG_H_ */
diff --git a/src/yang.l b/src/yang.l
index 3f38c84..58b6ec5 100644
--- a/src/yang.l
+++ b/src/yang.l
@@ -65,7 +65,7 @@
 "position" { return POSITION_KEYWORD; }

 "prefix" { return PREFIX_KEYWORD; }

 "presence" { return PRESENCE_KEYWORD; }

-"range" { BEGIN RANGE; return RANGE_KEYWORD; }

+"range" { return RANGE_KEYWORD; }

 "reference" { return REFERENCE_KEYWORD; }

 "refine" { BEGIN PATH; return REFINE_KEYWORD; }

 "require-instance" { return REQUIRE_INSTANCE_KEYWORD; }

diff --git a/src/yang.y b/src/yang.y
index a86d585..5cf4bd5 100644
--- a/src/yang.y
+++ b/src/yang.y
@@ -161,6 +161,7 @@
 %type <i> ordered_by_arg_str

 %type <v> length_arg_str

 %type <v> pattern_arg_str

+%type <v> range_arg_str

 %type <nodes> container_opt_stmt

 %type <nodes> anyxml_opt_stmt

 %type <nodes> choice_opt_stmt

@@ -642,12 +643,14 @@
   |  string_1

   ;

 

-range_stmt: RANGE_KEYWORD sep range_arg_str range_end; 

+range_stmt: RANGE_KEYWORD sep range_arg_str range_end { actual = $3;

+                                                        actual_type = RANGE_KEYWORD;

+                                                      }

 

 

 range_end: ';'

-  |  '{' start_check

-         message_opt_stmt  {free_check();}

+  |  '{' stmtsep

+         message_opt_stmt

       '}'

    ;

 

@@ -1659,23 +1662,15 @@
   | stmtend 

   ;

 

-range_arg_str: range_part1 range_part_opt;

-  |  string_1

-  ;

-

-range_part_opt: %empty 

-  | range_part_opt '|' optsep range_part1 ;

-

-range_part1: range_boundary range_part2;

-

-range_part2: %empty 

-  | DOUBLEDOT optsep range_boundary;

-

-range_boundary: MIN_KEYWORD optsep

-  | MAX_KEYWORD optsep

-  | integer_value optsep

-  | DECIMAL optsep

-  ;

+range_arg_str: string { if (read_all) {

+                          $$ = actual;

+                          if (!(actual = yang_read_range(module, actual, s, yylineno))) {

+                             YYERROR;

+                          }

+                          actual_type = RANGE_KEYWORD;

+                          s = NULL;

+                        }

+                      }

 

 absolute_schema_nodeid: "/" node_identifier { if (read_all) {

                                                 if (s) {