validators.go raw

   1  package tri
   2  
   3  import (
   4  	"time"
   5  	"reflect"
   6  	"errors"
   7  	"fmt"
   8  	"unicode"
   9  )
  10  
  11  // Validate checks to ensure the contents of this node type satisfy constraints.
  12  // Brief only contains one thing, so we make sure it has it - one string. This string may not contain any type of control characters, and is limited to 80 characters in length.
  13  func (r *Brief) Validate() error {
  14  
  15  	R := (*r)
  16  	if len(R) != 1 {
  17  		return errors.New("Brief field must have (only) one item")
  18  	}
  19  	s, ok := R[0].(string)
  20  	if !ok {
  21  		return errors.New("Brief's mandatory field is not a string")
  22  	}
  23  	if len(s) > 80 {
  24  		return errors.New("Brief's text may not be over 80 characters in length")
  25  	}
  26  	for i, x := range s {
  27  		if unicode.IsControl(x) {
  28  			return fmt.Errorf("Brief text may not contain any control characters, one found at position %d", i)
  29  		}
  30  	}
  31  	return nil
  32  }
  33  
  34  // Validate checks to ensure the contents of this node type satisfy constraints.
  35  // This validator only has to check the elements of the slice are zero or more Command items, and a valid name at index 0.
  36  func (r *Command) Validate() error {
  37  
  38  	R := *r
  39  	if len(R) < 1 {
  40  		return errors.New("empty Command")
  41  	}
  42  	s, ok := R[0].(string)
  43  	if !ok {
  44  		return fmt.Errorf("first element of Command must be a string")
  45  	}
  46  	if e := ValidName(s); e != nil {
  47  		return fmt.Errorf("error in name of Command: %v", e)
  48  	}
  49  	// validSet is an array of 4 elements that represent the presence of the 4 mandatory parts.
  50  	var validSet [2]bool
  51  	brief, handler := 0, 1
  52  	var singleSet [4]bool
  53  	usage, short, help, examples := 0, 1, 2, 3
  54  	for i, x := range R[1:] {
  55  		switch c := x.(type) {
  56  		case Short:
  57  			if singleSet[short] {
  58  				return fmt.Errorf("only one Short field allowed in Command")
  59  			}
  60  			singleSet[short] = true
  61  
  62  			e := c.Validate()
  63  			if e != nil {
  64  				return fmt.Errorf("error in Command at index %d: %v", i, e)
  65  			}
  66  		case Brief:
  67  			if validSet[brief] {
  68  				return fmt.Errorf("only one Brief permitted in a Command, second found at index %d", i)
  69  			}
  70  			validSet[brief] = true
  71  			e := c.Validate()
  72  			if e != nil {
  73  				return fmt.Errorf("error in Command at index %d: %v", i, e)
  74  			}
  75  		case Usage:
  76  			if singleSet[usage] {
  77  				return fmt.Errorf("only one Usage field allowed in Command")
  78  			}
  79  			singleSet[usage] = true
  80  			e := c.Validate()
  81  			if e != nil {
  82  				return fmt.Errorf("error in Command at index %d: %v", i, e)
  83  			}
  84  		case Help:
  85  			if singleSet[help] {
  86  				return fmt.Errorf("only one Help field allowed in Command")
  87  			}
  88  			singleSet[help] = true
  89  
  90  			e := c.Validate()
  91  			if e != nil {
  92  				return fmt.Errorf("error in Command at index %d: %v", i, e)
  93  			}
  94  		case Examples:
  95  			if singleSet[examples] {
  96  				return fmt.Errorf("only one Examples field allowed in Command")
  97  			}
  98  			singleSet[examples] = true
  99  
 100  			e := c.Validate()
 101  			if e != nil {
 102  				return fmt.Errorf("error in Command at index %d: %v", i, e)
 103  			}
 104  		case Var:
 105  			e := c.Validate()
 106  			if e != nil {
 107  				return fmt.Errorf("error in Command at index %d: %v", i, e)
 108  			}
 109  		case Trigger:
 110  			e := c.Validate()
 111  			if e != nil {
 112  				return fmt.Errorf("error in Command at index %d: %v", i, e)
 113  			}
 114  		case func(*Tri) int:
 115  			if validSet[handler] {
 116  				return fmt.Errorf("only one Handler permitted in a Command, second found at index %d", i)
 117  			}
 118  			validSet[handler] = true
 119  			if c == nil {
 120  				return fmt.Errorf("nil handler in Command found at index %d", i)
 121  			}
 122  		default:
 123  			return fmt.Errorf("invalid type present in Command: %v", reflect.TypeOf(c))
 124  		}
 125  	}
 126  	if !validSet[brief] {
 127  		return errors.New("Brief field must be present")
 128  	}
 129  	if !validSet[handler] {
 130  		return errors.New("Command must have a handler")
 131  	}
 132  	return nil
 133  }
 134  
 135  // Validate checks to ensure the contents of this node type satisfy constraints.
 136  // This validator only triggers the validator on its elements.
 137  func (r *Commands) Validate() error {
 138  
 139  	R := (*r)
 140  	for i, x := range R {
 141  		e := x.Validate()
 142  		if e != nil {
 143  			return fmt.Errorf("error in element %d of Commands list: %v", i, e)
 144  		}
 145  	}
 146  	return nil
 147  }
 148  
 149  // Validate checks to ensure the contents of this node type satisfy constraints.
 150  // The only constraint on the Default subtype is that it contains at only one element, the value is checked for correct typing by the Commands validator.
 151  func (r *Default) Validate() error {
 152  
 153  	R := (*r)
 154  	if len(R) != 1 {
 155  		return errors.New("the Default container must only contain one element")
 156  	}
 157  	return nil
 158  }
 159  
 160  // Validate checks to ensure the contents of this node type satisfy constraints.
 161  // The constraint of DefaultCommand is that it has at least one element, and that the 0 element is a string. The check for the command name's presence in the Commands set is in the Tri validator.
 162  func (r *DefaultCommand) Validate() error {
 163  
 164  	R := (*r)
 165  	if len(R) != 1 {
 166  		return errors.New(
 167  			"the DefaultCommand element must contain only one element")
 168  	}
 169  	s, ok := R[0].(string)
 170  	if !ok {
 171  		return errors.New("element 0 of DefaultCommand must be a string")
 172  	}
 173  	if e := ValidName(s); e != nil {
 174  		return fmt.Errorf("error in DefaultCommand: %v", e)
 175  	}
 176  	return nil
 177  }
 178  
 179  // Validate checks to ensure the contents of this node type satisfy constraints.
 180  // RunAfter is a simple flag that indicates by existence of an empty value, so it is an error if it has anything inside it.
 181  func (r *DefaultOn) Validate() error {
 182  
 183  	R := *r
 184  	if len(R) > 0 {
 185  		return errors.New(
 186  			"DefaultOn may not contain anything, empty declaration only")
 187  	}
 188  	return nil
 189  }
 190  
 191  // Validate checks to ensure the contents of this node type satisfy constraints.
 192  // The constraints of examples are minimum two elements and all elements are strings. The intent is the even numbered items are snippets showing invocation and a description string of the same format as Brief{}.
 193  func (r *Examples) Validate() error {
 194  
 195  	R := *r
 196  	if len(R) < 2 {
 197  		return errors.New("Examples field may not be empty")
 198  	}
 199  	if len(R)%2 != 0 {
 200  		return fmt.Errorf(
 201  			"Examples must be in pairs, odd number of elements found")
 202  	}
 203  	for i, x := range R {
 204  		_, ok := x.(string)
 205  		if !ok {
 206  			return fmt.Errorf(
 207  				"Examples elements may only be strings, element %d is not a string", i)
 208  		}
 209  	}
 210  
 211  	for i := 1; i <= len(R)-1; i += 2 {
 212  		if len(R[i-1].(string)) > 40 {
 213  			return errors.New(
 214  				"Examples example text may not be over 4 characters in length")
 215  		}
 216  		if len(R[i].(string)) > 80 {
 217  			return errors.New(
 218  				"Examples explainer text may not be over 80 characters in length")
 219  		}
 220  		for i, x := range R[i].(string) {
 221  			if unicode.IsControl(x) {
 222  				return fmt.Errorf(
 223  					"Examples even numbered field string may not contain control characters, one found at index %d", i)
 224  			}
 225  		}
 226  	}
 227  	return nil
 228  }
 229  
 230  // Validate checks to ensure the contents of this node type satisfy constraints.
 231  // A group must contain one string, anything else is invalid. It also has the same limitation as a name - only letters.
 232  func (r *Group) Validate() error {
 233  
 234  	R := *r
 235  	if len(R) != 1 {
 236  		return errors.New("Group must (only) contain one element")
 237  	}
 238  	s, ok := R[0].(string)
 239  	if !ok {
 240  		return errors.New("Group element must be a string")
 241  	}
 242  	if e := ValidName(s); e != nil {
 243  		return fmt.Errorf("error in name of Group: %v", e)
 244  	}
 245  	return nil
 246  }
 247  
 248  // Validate checks to ensure the contents of this node type satisfy constraints.
 249  // Help may only contain one string. It will be parsed as markdown format and possibly can be set to style it with ANSI codes.
 250  func (r *Help) Validate() error {
 251  
 252  	R := *r
 253  	if len(R) != 1 {
 254  		return errors.New("Help field must contain (only) one item")
 255  	}
 256  	_, ok := R[0].(string)
 257  	if !ok {
 258  		return errors.New("Help field element is not a string")
 259  	}
 260  	return nil
 261  }
 262  
 263  // Validate checks to ensure the contents of this node type satisfy constraints.
 264  // RunAfter is a simple flag that indicates by existence of an empty value, so it is an error if it has anything inside it.
 265  func (r *RunAfter) Validate() error {
 266  
 267  	R := *r
 268  	if len(R) > 0 {
 269  		return errors.New(
 270  			"RunAfter may not contain anything, empty declaration only")
 271  	}
 272  	return nil
 273  }
 274  
 275  // Validate checks to ensure the contents of this node type satisfy constraints.
 276  // Short names contain only a single Rune variable.
 277  func (r *Short) Validate() error {
 278  
 279  	R := *r
 280  	if len(R) != 1 {
 281  		return errors.New("Short name item must contain (only) one item")
 282  	}
 283  	s, ok := R[0].(rune)
 284  	if !ok {
 285  		return errors.New("Short's element must be a rune (enclose in '')")
 286  	}
 287  	if !(unicode.IsDigit(s) || unicode.IsLetter(s)) {
 288  		return errors.New("Short element is not a letter or number")
 289  	}
 290  	return nil
 291  }
 292  
 293  // Validate checks to ensure the contents of this node type satisfy constraints.
 294  // Slot may only contain one type of element. The type check is in the Var, here we only ensure the slots contain pointers to the same type, the parser will put the final parsed value in all of them. Multiple variables are permitted here to enable the configuration of more than one application.
 295  func (r *Slot) Validate() error {
 296  
 297  	R := *r
 298  	var slotTypes []reflect.Type
 299  	for _, x := range R {
 300  		slotTypes = append(slotTypes, reflect.TypeOf(x))
 301  	}
 302  	for i, x := range slotTypes {
 303  		if i > 0 {
 304  			if slotTypes[i] != slotTypes[i-1] {
 305  				return fmt.Errorf("slot contains more than one type of variable, found %v at index %d", x, i)
 306  			}
 307  		}
 308  	}
 309  	for _, x := range R {
 310  		if reflect.ValueOf(x).Kind() != reflect.Ptr {
 311  			return fmt.Errorf("slot contains non-pointer type")
 312  		}
 313  	}
 314  
 315  	return nil
 316  }
 317  
 318  // Validate checks to ensure the contents of this node type satisfy constraints.
 319  // Terminates is a flag value, and may not contain anything.
 320  func (r *Terminates) Validate() error {
 321  
 322  	R := *r
 323  	if len(R) > 0 {
 324  		return errors.New("Terminates type may not contain anything")
 325  	}
 326  	return nil
 327  }
 328  
 329  // Validate checks to ensure the contents of this node type satisfy constraints.
 330  // A Tri, the base type, in a declaration must contain a name as first element, a Brief, Version and a Commands item, and only one of each. Also, this and several other subtypes of Tri.
 331  func (r *Tri) Validate() error {
 332  	R := *r
 333  	if len(R) < 3 {
 334  		return errors.New("a Tri must contain at least 3 elements: name, Brief and Version")
 335  	}
 336  	// validSet is an array of 4 elements that represent the presence of the 4 mandatory parts.
 337  	var validSet [2]bool
 338  	brief, version := 0, 1
 339  	var singleSet [3]bool
 340  	defcom, commands := 0, 1
 341  	n, ok := R[0].(string)
 342  	if !ok {
 343  		return errors.New("first element of a Tri must be a string")
 344  	}
 345  	if e := ValidName(n); e != nil {
 346  		return fmt.Errorf("error in name of Tri: %v", e)
 347  	}
 348  
 349  	// The mandatory elements also may not be repeated:
 350  	for i, x := range R {
 351  		if i == 0 {
 352  			continue
 353  		}
 354  		switch y := x.(type) {
 355  		case Brief:
 356  			if validSet[brief] {
 357  				return fmt.Errorf(
 358  					"Tri contains more than one Brief, second found at index %d", i)
 359  			}
 360  			validSet[brief] = true
 361  			if e := y.Validate(); e != nil {
 362  				return fmt.Errorf("Tri field %d: %s", i, e)
 363  			}
 364  		case Version:
 365  			if validSet[version] {
 366  				return fmt.Errorf(
 367  					"Tri contains more than one Version, second found at index %d", i)
 368  			}
 369  			validSet[version] = true
 370  			if e := y.Validate(); e != nil {
 371  				return fmt.Errorf("Tri field %d: %s", i, e)
 372  			}
 373  			validSet[version] = true
 374  		case Commands:
 375  			if singleSet[commands] {
 376  				return fmt.Errorf(
 377  					"Tri contains more than one Commands, second found at index %d", i)
 378  			}
 379  			singleSet[commands] = true
 380  			e := y.Validate()
 381  			if e != nil {
 382  				return fmt.Errorf("error in Tri field %d: %s", i, e)
 383  			}
 384  		case Var:
 385  			e := y.Validate()
 386  			if e != nil {
 387  				return fmt.Errorf("error in Tri at index %d: %v", i, e)
 388  			}
 389  		case Trigger:
 390  			e := y.Validate()
 391  			if e != nil {
 392  				return fmt.Errorf("error in Tri at index %d: %v", i, e)
 393  			}
 394  		case DefaultCommand:
 395  			if singleSet[defcom] {
 396  				return fmt.Errorf(
 397  					"Tri contains more than one DefaultCommand, second found at index %d", i)
 398  			}
 399  			singleSet[defcom] = true
 400  			e := y.Validate()
 401  			if e != nil {
 402  				return fmt.Errorf("Tri field %d: %s", i, e)
 403  			}
 404  			commname := y[0].(string)
 405  			// DefaultCommand must match in its name one of the Command items in also present Commands array
 406  			foundComm := false
 407  			foundDefComm := false
 408  			for _, a := range R {
 409  				switch c := a.(type) {
 410  				case Commands:
 411  					foundComm = true
 412  					for _, b := range c {
 413  						if b[0].(string) == commname {
 414  							foundDefComm = true
 415  						}
 416  					}
 417  				default:
 418  				}
 419  			}
 420  			if !foundComm {
 421  				return errors.New("DefaultCommand with no Commands array present")
 422  			} else if !foundDefComm {
 423  				return errors.New("DefaultCommand found with no matching Command")
 424  			}
 425  
 426  		default:
 427  			return fmt.Errorf(
 428  				"Tri contains an element type it may not contain at index %d", i)
 429  		}
 430  	}
 431  	switch {
 432  	case !validSet[brief]:
 433  		return errors.New("Tri is missing its Brief field")
 434  	case !validSet[version]:
 435  		return errors.New("Tri is missing its Version field")
 436  	}
 437  	return nil
 438  }
 439  
 440  // Validate checks to ensure the contents of this node type satisfy constraints.
 441  // Trigger must contain (one) name, Brief and Handler, and nothing other than these and Short, Usage, Help, Default, Terminates, RunAfter.
 442  func (r *Trigger) Validate() error {
 443  
 444  	R := *r
 445  	if len(R) < 3 {
 446  		return errors.New(
 447  			"Trigger must contain a name, Brief and Handler at minimum")
 448  	}
 449  	name, ok := R[0].(string)
 450  	if !ok {
 451  		return errors.New("first element of Trigger must be the name")
 452  	} else if e := ValidName(name); e != nil {
 453  		return fmt.Errorf("Invalid Name in Trigger at index 0: %v", e)
 454  	}
 455  	// validSet is an array that represent the presence of the mandatory parts.
 456  	var validSet [2]bool
 457  	brief, handler := 0, 1
 458  	var singleSet [7]bool
 459  	short, usage, help, defon, terminates, runafter, group := 0, 1, 2, 3, 4, 5, 6
 460  	for i, x := range R[1:] {
 461  
 462  		switch y := x.(type) {
 463  
 464  		case Brief:
 465  			if validSet[brief] {
 466  				return fmt.Errorf("Trigger may (only) contain one Brief, second found at index %d", i)
 467  			} else {
 468  				validSet[brief] = true
 469  			}
 470  			if e := y.Validate(); e != nil {
 471  				return fmt.Errorf(
 472  					"Trigger contains invalid element at %d - %s", i, e)
 473  			}
 474  
 475  		case func(*Tri) int:
 476  			if validSet[handler] {
 477  				return fmt.Errorf(
 478  					"Trigger may (only) contain one Handler, second found at index %d", i)
 479  			} else {
 480  				validSet[handler] = true
 481  			}
 482  			if y == nil {
 483  				return fmt.Errorf("Handler at index %d may not be nil", i)
 484  			}
 485  
 486  		case Short:
 487  			if singleSet[short] {
 488  				return fmt.Errorf("Trigger may only contain one Short, extra found at index %d", i)
 489  			}
 490  			singleSet[short] = true
 491  			if e := y.Validate(); e != nil {
 492  				return fmt.Errorf(
 493  					"Trigger contains invalid element at %d - %s", i, e)
 494  			}
 495  
 496  		case Usage:
 497  			if singleSet[usage] {
 498  				return fmt.Errorf("Trigger may only contain one Usage, extra found at index %d", i)
 499  			}
 500  			singleSet[usage] = true
 501  			if e := y.Validate(); e != nil {
 502  				return fmt.Errorf(
 503  					"Trigger contains invalid element at %d - %s", i, e)
 504  			}
 505  
 506  		case Help:
 507  			if singleSet[help] {
 508  				return fmt.Errorf("Trigger may only contain one Help, extra found at index %d", i)
 509  			}
 510  			singleSet[help] = true
 511  			if e := y.Validate(); e != nil {
 512  				return fmt.Errorf(
 513  					"Trigger contains invalid element at %d - %s", i, e)
 514  			}
 515  
 516  		case DefaultOn:
 517  			if singleSet[defon] {
 518  				return fmt.Errorf("Trigger may only contain one DefaultOn, extra found at index %d", i)
 519  			}
 520  			singleSet[defon] = true
 521  			if e := y.Validate(); e != nil {
 522  				return fmt.Errorf(
 523  					"Trigger contains invalid element at %d - %s", i, e)
 524  			}
 525  
 526  		case Terminates:
 527  			if singleSet[terminates] {
 528  				return fmt.Errorf("Trigger may only contain one Terminates, extra found at index %d", i)
 529  			}
 530  			singleSet[terminates] = true
 531  			if e := y.Validate(); e != nil {
 532  				return fmt.Errorf(
 533  					"Trigger contains invalid element at %d - %s", i, e)
 534  			}
 535  
 536  		case RunAfter:
 537  			if singleSet[runafter] {
 538  				return fmt.Errorf("Trigger may only contain one RunAfter, extra found at index %d", i)
 539  			}
 540  			singleSet[runafter] = true
 541  			if e := y.Validate(); e != nil {
 542  				return fmt.Errorf(
 543  					"Trigger contains invalid element at %d - %s", i, e)
 544  			}
 545  
 546  		case Group:
 547  			if singleSet[group] {
 548  				return fmt.Errorf(
 549  					"Trigger may only contain one Group, extra found at index %d", i)
 550  			}
 551  			singleSet[group] = true
 552  			if e := y.Validate(); e != nil {
 553  				return fmt.Errorf(
 554  					"Trigger contains invalid element at %d - %s", i, e)
 555  			}
 556  
 557  		default:
 558  			return fmt.Errorf(
 559  				"found invalid item type at element %d in a Trigger", i)
 560  		}
 561  	}
 562  	if !(validSet[brief] && validSet[handler]) {
 563  		return errors.New("Trigger must contain one each of Brief and Handler")
 564  	}
 565  	return nil
 566  }
 567  
 568  // Validate checks to ensure the contents of this node type satisfy constraints.
 569  // Usage fields contain only one string of no more than 80 characters and no control characters.
 570  func (r *Usage) Validate() error {
 571  	R := *r
 572  	if len(R) != 1 {
 573  		return errors.New("Usage field must contain (only) one element")
 574  	}
 575  	s, ok := R[0].(string)
 576  	if !ok {
 577  		return errors.New("Usage field element is not a string")
 578  	}
 579  	if ll := len(s); ll > 80 {
 580  		return fmt.Errorf("Usage string is %d chars long, may not be longer than 80", ll)
 581  	}
 582  	for i, x := range s {
 583  		if unicode.IsControl(x) {
 584  			return fmt.Errorf(
 585  				"Usage field string may not contain control characters, one found at index %d", i)
 586  		}
 587  	}
 588  	return nil
 589  }
 590  
 591  // Validate checks to ensure the contents of this node type satisfy constraints.
 592  // Var must contain name, Brief and Slot, and optionally, Short, Usage, Help and Default. The type in the Slot and the Default must be the same.
 593  func (r *Var) Validate() error {
 594  
 595  	R := *r
 596  	if len(R) < 3 {
 597  		return errors.New(
 598  			"Var must contain a name, Brief and Slot at minimum")
 599  	}
 600  	name, ok := R[0].(string)
 601  	if !ok {
 602  		return errors.New("first element of Var must be the name")
 603  	} else if e := ValidName(name); e != nil {
 604  		return fmt.Errorf("Invalid Name in Var at index 0: %v", e)
 605  	}
 606  	// validSet is an array that represent the presence of the mandatory parts.
 607  	var validSet [2]bool
 608  	brief, slot := 0, 1
 609  	// singleSet is an array representing the optional elements that may not be more than one inside a Var
 610  	var singleSet [5]bool
 611  	short, usage, help, def, group := 0, 1, 2, 3, 4
 612  	for i, x := range R[1:] {
 613  
 614  		switch y := x.(type) {
 615  
 616  		case Brief:
 617  			if validSet[brief] {
 618  				return fmt.Errorf("Var may must (only) contain one Brief, second found at index %d", i)
 619  			} else {
 620  				validSet[brief] = true
 621  			}
 622  			if e := y.Validate(); e != nil {
 623  				return fmt.Errorf(
 624  					"Var contains invalid element at %d - %s", i, e)
 625  			}
 626  
 627  		case Short:
 628  			if singleSet[short] {
 629  				return fmt.Errorf("Var may only contain one Short, extra found at index %d", i)
 630  			}
 631  			singleSet[short] = true
 632  			if e := y.Validate(); e != nil {
 633  				return fmt.Errorf(
 634  					"Var contains invalid element at %d - %s", i, e)
 635  			}
 636  
 637  		case Usage:
 638  			if singleSet[usage] {
 639  				return fmt.Errorf("Var may only contain one Usage, extra found at index %d", i)
 640  			}
 641  			singleSet[usage] = true
 642  			if e := y.Validate(); e != nil {
 643  				return fmt.Errorf(
 644  					"Var contains invalid element at %d - %s", i, e)
 645  			}
 646  
 647  		case Help:
 648  			if singleSet[help] {
 649  				return fmt.Errorf("Var may only contain one Help, extra found at index %d", i)
 650  			}
 651  			singleSet[help] = true
 652  			if e := y.Validate(); e != nil {
 653  				return fmt.Errorf(
 654  					"Var contains invalid element at %d - %s", i, e)
 655  			}
 656  
 657  		case Default:
 658  			if singleSet[def] {
 659  				return fmt.Errorf("Var may only contain one Default, extra found at index %d", i)
 660  			}
 661  			singleSet[def] = true
 662  			if e := y.Validate(); e != nil {
 663  				return fmt.Errorf(
 664  					"Var contains invalid element at %d - %s", i, e)
 665  			}
 666  			for _, z := range R {
 667  				s, ok := z.(Slot)
 668  				if ok {
 669  					switch s[0].(type) {
 670  					case *string:
 671  						_, ok := y[0].(string)
 672  						if !ok {
 673  							return errors.New("slot is not same type as default")
 674  						}
 675  					case *int:
 676  						_, ok := y[0].(int)
 677  						if !ok {
 678  							return errors.New("slot is not same type as default")
 679  						}
 680  					case *uint32:
 681  						_, ok := y[0].(uint32)
 682  						if !ok {
 683  							return errors.New("slot is not same type as default")
 684  						}
 685  					case *float64:
 686  						_, ok := y[0].(float64)
 687  						if !ok {
 688  							return errors.New("slot is not same type as default")
 689  						}
 690  					case *[]string:
 691  						_, ok := y[0].([]string)
 692  						if !ok {
 693  							return errors.New("slot is not same type as default")
 694  						}
 695  					case *time.Duration:
 696  						_, ok := y[0].(time.Duration)
 697  						if !ok {
 698  							return errors.New("slot is not same type as default")
 699  						}
 700  					}
 701  					// *s[0] = *y[0]
 702  				}
 703  			}
 704  
 705  		case Slot:
 706  			if validSet[slot] {
 707  				return fmt.Errorf("Var may only contain one Slot, extra found at index %d", i)
 708  			}
 709  			validSet[slot] = true
 710  			if e := y.Validate(); e != nil {
 711  				return fmt.Errorf(
 712  					"Var contains invalid element at %d - %s", i, e)
 713  			}
 714  
 715  		case Group:
 716  			if singleSet[group] {
 717  				return fmt.Errorf(
 718  					"Var may only contain one Group, extra found at index %d", i)
 719  			}
 720  			singleSet[group] = true
 721  			if e := y.Validate(); e != nil {
 722  				return fmt.Errorf(
 723  					"Var contains invalid element at %d - %s", i, e)
 724  			}
 725  		default:
 726  			return fmt.Errorf(
 727  				"found invalid item type at element %d in a Var", i)
 728  		}
 729  	}
 730  	if !(validSet[brief] && validSet[slot]) {
 731  		return errors.New("Var must contain one each of Brief and Slot")
 732  	}
 733  	// TODO: check that Default value can be assigned to dereferenced Slot variable
 734  
 735  	return nil
 736  }
 737  
 738  // Validate checks to ensure the contents of this node type satisfy constraints.
 739  // A version item contains three integers and an optional (less than 16 character) string, and the numbers may not be more than 99.
 740  func (r *Version) Validate() error {
 741  
 742  	R := *r
 743  	if len(R) > 4 {
 744  		return errors.New("Version field may not contain more than 4 fields")
 745  	}
 746  	if len(R) < 3 {
 747  		return errors.New("Version field must contain at least 3 fields")
 748  	}
 749  	for i, x := range R[:3] {
 750  		n, ok := x.(int)
 751  		if !ok {
 752  			return fmt.Errorf("Version field %d is not an integer: %d", i, n)
 753  		}
 754  		if n > 99 {
 755  			return fmt.Errorf("Version field %d value is over 99: %d", i, n)
 756  		}
 757  	}
 758  	if len(R) > 3 {
 759  		s, ok := R[3].(string)
 760  		if !ok {
 761  			return fmt.Errorf("optional field 4 of Version is not a string")
 762  		} else {
 763  			for i, x := range s {
 764  				if !(unicode.IsLetter(x) || unicode.IsDigit(x)) {
 765  					return fmt.Errorf(
 766  						"optional field 4 of Version contains other than letters and numbers at position %d: '%v,", i, x)
 767  				}
 768  			}
 769  		}
 770  	}
 771  	return nil
 772  }
 773  
 774  // ValidName checks that a Tri name element that should be a name only contains letters.
 775  func ValidName(s string) error {
 776  
 777  	if len(s) < 3 {
 778  		return errors.New("name is less than 3 characters long")
 779  	}
 780  	for i, x := range s {
 781  		if !unicode.IsLetter(x) {
 782  			return fmt.Errorf(
 783  				"element %d, '%v' of name is not a letter", i, x)
 784  		}
 785  	}
 786  	return nil
 787  }
 788