...
Tawesoft Logo

Source file src/tawesoft.co.uk/go/glcaps/tag.go

Documentation: src/tawesoft.co.uk/go/glcaps/tag.go

     1  package glcaps
     2  
     3  import (
     4      "fmt"
     5      "strconv"
     6      "strings"
     7  )
     8  
     9  func operationStringEq  (a string,   b string) bool { return a == b }
    10  func operationStringNeq (a string,   b string) bool { return a != b }
    11  
    12  type command interface{
    13      evalBool  (b *Binding, extensions Extensions) bool
    14      evalInt   (b *Binding, extensions Extensions) int
    15      evalFloat (b *Binding, extensions Extensions) float32
    16      evalString(b *Binding, extensions Extensions) string
    17      hasBoolRepresentation() bool
    18      hasIntRepresentation() bool
    19      hasFloatRepresentation() bool
    20      hasStringRepresentation() bool
    21  }
    22  
    23  type requirement interface{
    24      evalBool  (field string, result bool)    error
    25      evalInt   (field string, result int)     error
    26      evalFloat (field string, result float32) error
    27      evalString(field string, result string) error
    28  }
    29  
    30  type tag struct {
    31      command command
    32      requirements []requirement
    33  }
    34  
    35  // ===[ requirementRequired ]================================================================[ requirementRequired ]===
    36  
    37  type requirementRequired struct {}
    38  
    39  func (r requirementRequired) evalBool(field string, result bool) error {
    40      if result { return nil }
    41      return fmt.Errorf("%s is required", field)
    42  }
    43  
    44  func (r requirementRequired) evalInt(field string, result int) error {
    45      panic("not an int")
    46  }
    47  
    48  func (r requirementRequired) evalFloat(field string, result float32) error {
    49      panic("not a float")
    50  }
    51  
    52  func (r requirementRequired) evalString(field string, result string) error {
    53      if len(result) > 0 { return nil }
    54      return fmt.Errorf("%s is required", field)
    55  }
    56  
    57  // ===[ requirementComparison ]============================================================[ requirementComparison ]===
    58  
    59  type requirementComparison struct {
    60      constant string
    61      symbol string
    62      operationi func(int, int)         bool
    63      operationf func(float32, float32) bool
    64      operations func(string, string)   bool
    65  }
    66  
    67  func (r requirementComparison) evalBool(field string, result bool) error {
    68      panic("not a bool")
    69  }
    70  
    71  func (r requirementComparison) evalInt(field string, result int) error {
    72      var i, err = strconv.ParseInt(r.constant, 10, 32)
    73      if err != nil { panic("not an integer constant") }
    74      
    75      if r.operationi(result, int(i)) { return nil }
    76      return fmt.Errorf("%s is %d but must be %s %s", field, result, r.symbol, r.constant)
    77  }
    78  
    79  func (r requirementComparison) evalFloat(field string, result float32) error {
    80      var f, err = strconv.ParseFloat(r.constant, 32)
    81      if err != nil { panic("not a float constant") }
    82      
    83      if r.operationf(result, float32(f)) { return nil }
    84      return fmt.Errorf("%s is %.2f but must be %s %s", field, result, r.symbol, r.constant)
    85  }
    86  
    87  func (r requirementComparison) evalString(field string, result string) error {
    88      if r.operations(result, r.constant) { return nil }
    89      return fmt.Errorf("%s is %s but must be %s %s", field, result, r.symbol, r.constant)
    90  }
    91  
    92  // ===[ commandValue ]==============================================================================[ commandValue ]===
    93  
    94  type commandValue struct {
    95      value string
    96  }
    97  
    98  func (c commandValue) evalBool(_ *Binding, _ Extensions) bool {
    99      switch c.value {
   100          case "true":  return true
   101          case "false": return false
   102          default: panic(fmt.Sprintf("not a boolean: '%s'", c.value))
   103      }
   104  }
   105  
   106  func (c commandValue) evalInt(_ *Binding, _ Extensions) int {
   107      var result, err = strconv.ParseInt(c.value, 10, 32)
   108      if err != nil { panic(fmt.Sprintf("not an integer: '%s'", c.value)) }
   109      return int(result)
   110  }
   111  
   112  func (c commandValue) evalFloat(_ *Binding, _ Extensions) float32 {
   113      var result, err = strconv.ParseFloat(c.value, 32)
   114      if err != nil { panic(fmt.Sprintf("not a float: '%s'", c.value)) }
   115      return float32(result)
   116  }
   117  
   118  func (c commandValue) evalString(_ *Binding, _ Extensions) string {
   119      return c.value
   120  }
   121  
   122  func (c commandValue) hasBoolRepresentation() bool {
   123      switch c.value {
   124          case "true":  return true
   125          case "false": return true
   126          default:      return false
   127      }
   128  }
   129  
   130  func (c commandValue) hasIntRepresentation() bool {
   131      var _, err = strconv.ParseInt(c.value, 10, 32)
   132      return err == nil
   133  }
   134  
   135  func (c commandValue) hasFloatRepresentation() bool {
   136      var hasRadix = (strings.IndexByte(c.value, '.') >= 0)
   137      var _, err = strconv.ParseFloat(c.value, 32)
   138      return err == nil && hasRadix
   139  }
   140  
   141  func (c commandValue) hasStringRepresentation() bool {
   142      return true
   143  }
   144  
   145  // ===[ commandBinaryBoolean ]==============================================================[ commandBinaryBoolean ]===
   146  
   147  type commandBinaryBoolean struct {
   148      a command
   149      b command
   150      operation func(bool, bool) bool
   151  }
   152  
   153  func (c commandBinaryBoolean) evalBool(b *Binding, e Extensions) bool {
   154      return c.operation(c.a.evalBool(b, e), c.b.evalBool(b, e))
   155  }
   156  
   157  func (c commandBinaryBoolean) evalInt(b *Binding, _ Extensions) int {
   158      panic("not an integer")
   159  }
   160  
   161  func (c commandBinaryBoolean) evalFloat(b *Binding, _ Extensions) float32 {
   162      panic("not a float")
   163  }
   164  
   165  func (c commandBinaryBoolean) evalString(_ *Binding, _ Extensions) string {
   166      panic("not a string")
   167  }
   168  
   169  func (c commandBinaryBoolean) hasBoolRepresentation() bool {
   170      return true
   171  }
   172  
   173  func (c commandBinaryBoolean) hasIntRepresentation() bool {
   174      return false
   175  }
   176  
   177  func (c commandBinaryBoolean) hasFloatRepresentation() bool {
   178      return false
   179  }
   180  
   181  func (c commandBinaryBoolean) hasStringRepresentation() bool {
   182      return false
   183  }
   184  
   185  // ===[ commandNot ]==================================================================================[ commandNot ]===
   186  
   187  type commandNot struct {
   188      inner command
   189  }
   190  
   191  func (c commandNot) evalBool(b *Binding, e Extensions) bool {
   192      return !c.inner.evalBool(b, e)
   193  }
   194  
   195  func (c commandNot) evalInt(b *Binding, _ Extensions) int {
   196      panic("not an integer")
   197  }
   198  
   199  func (c commandNot) evalFloat(b *Binding, _ Extensions) float32 {
   200      panic("not a float")
   201  }
   202  
   203  func (c commandNot) evalString(b *Binding, _ Extensions) string {
   204      panic("not a string")
   205  }
   206  
   207  func (c commandNot) hasBoolRepresentation() bool {
   208      return true
   209  }
   210  
   211  func (c commandNot) hasIntRepresentation() bool {
   212      return false
   213  }
   214  
   215  func (c commandNot) hasFloatRepresentation() bool {
   216      return false
   217  }
   218  
   219  func (c commandNot) hasStringRepresentation() bool {
   220      return false
   221  }
   222  
   223  // ===[ commandCompare ]==========================================================================[ commandCompare ]===
   224  
   225  type commandCompare struct {
   226      a command
   227      b command
   228      operationi func(int, int)         bool
   229      operationf func(float32, float32) bool
   230      operations func(string,  string)  bool
   231  }
   232  
   233  func (c commandCompare) evalBool(b *Binding, e Extensions) bool {
   234      if c.a.hasFloatRepresentation() && c.b.hasFloatRepresentation() {
   235          return c.operationf(c.a.evalFloat(b, e), c.b.evalFloat(b, e))
   236      } else if c.a.hasIntRepresentation() && c.b.hasIntRepresentation() {
   237          return c.operationi(c.a.evalInt(b, e), c.b.evalInt(b, e))
   238      } else if c.a.hasStringRepresentation() && c.b.hasStringRepresentation() {
   239          if c.operations != nil {
   240              return c.operations(c.a.evalString(b, e), c.b.evalString(b, e))
   241          } else {
   242              panic(fmt.Sprintf("string operation not defined for this comparison"))
   243          }
   244      } else {
   245          panic(fmt.Sprintf("cannot compare mismatched types (%+v and %+v)", c.a, c.b))
   246      }
   247  }
   248  
   249  func (c commandCompare) evalInt(b *Binding, e Extensions) int {
   250      panic("not an integer")
   251  }
   252  
   253  func (c commandCompare) evalFloat(b *Binding, e Extensions) float32 {
   254      panic("not a float")
   255  }
   256  
   257  func (c commandCompare) evalString(b *Binding, e Extensions) string {
   258      panic("not a string")
   259  }
   260  
   261  func (c commandCompare) hasBoolRepresentation() bool {
   262      return false
   263  }
   264  
   265  func (c commandCompare) hasIntRepresentation() bool {
   266      return c.a.hasIntRepresentation() && c.b.hasIntRepresentation()
   267  }
   268  
   269  func (c commandCompare) hasFloatRepresentation() bool {
   270      return c.a.hasFloatRepresentation() && c.b.hasFloatRepresentation()
   271  }
   272  
   273  func (c commandCompare) hasStringRepresentation() bool {
   274      return c.a.hasStringRepresentation() && c.b.hasStringRepresentation()
   275  }
   276  
   277  // ===[ commandExt ]==================================================================================[ commandExt ]===
   278  
   279  type commandExt struct {
   280      name string
   281  }
   282  
   283  func (c commandExt) evalBool(b *Binding, e Extensions) bool {
   284      return e.Contains(c.name)
   285  }
   286  
   287  func (c commandExt) evalInt(b *Binding, e Extensions) int {
   288      panic("not an integer")
   289  }
   290  
   291  func (c commandExt) evalFloat(b *Binding, e Extensions) float32 {
   292      panic("not a float")
   293  }
   294  
   295  func (c commandExt) evalString(b *Binding, e Extensions) string {
   296      panic("not a string")
   297  }
   298  
   299  func (c commandExt) hasBoolRepresentation() bool {
   300      return true
   301  }
   302  
   303  func (c commandExt) hasIntRepresentation() bool {
   304      return false
   305  }
   306  
   307  func (c commandExt) hasFloatRepresentation() bool {
   308      return false
   309  }
   310  
   311  func (c commandExt) hasStringRepresentation() bool {
   312      return false
   313  }
   314  
   315  // ===[ commandGetIntegerv ]==================================================================[ commandGetIntegerV ]===
   316  
   317  type commandGetIntegerv struct {
   318      name string
   319  }
   320  
   321  func (c commandGetIntegerv) evalBool(b *Binding, e Extensions) bool {
   322      panic("not a bool")
   323  }
   324  
   325  func (c commandGetIntegerv) evalInt(b *Binding, e Extensions) int {
   326      var result int32
   327      var id, exists = glconstants[c.name]
   328      if !exists { return 0 }
   329      b.GetIntegerv(id, &result)
   330      return int(result)
   331  }
   332  
   333  func (c commandGetIntegerv) evalFloat(b *Binding, e Extensions) float32 {
   334      panic("not a float")
   335  }
   336  
   337  func (c commandGetIntegerv) evalString(b *Binding, e Extensions) string {
   338      panic("not a string")
   339  }
   340  
   341  func (c commandGetIntegerv) hasBoolRepresentation() bool {
   342      return false
   343  }
   344  
   345  func (c commandGetIntegerv) hasIntRepresentation() bool {
   346      return true
   347  }
   348  
   349  func (c commandGetIntegerv) hasFloatRepresentation() bool {
   350      return false
   351  }
   352  
   353  func (c commandGetIntegerv) hasStringRepresentation() bool {
   354      return false
   355  }
   356  
   357  // ===[ commandGetFloatv ]======================================================================[ commandGetFloatV ]===
   358  
   359  type commandGetFloatv struct {
   360      name string
   361  }
   362  
   363  func (c commandGetFloatv) evalBool(b *Binding, e Extensions) bool {
   364      panic("not a bool")
   365  }
   366  
   367  func (c commandGetFloatv) evalInt(b *Binding, e Extensions) int {
   368      panic("not an int")
   369  }
   370  
   371  func (c commandGetFloatv) evalFloat(b *Binding, e Extensions) float32 {
   372      var result float32
   373      var id, exists = glconstants[c.name]
   374      if !exists { return 0.0 }
   375      b.GetFloatv(id, &result)
   376      return result
   377  }
   378  
   379  func (c commandGetFloatv) evalString(b *Binding, e Extensions) string {
   380      panic("not a string")
   381  }
   382  
   383  func (c commandGetFloatv) hasBoolRepresentation() bool {
   384      return false
   385  }
   386  
   387  func (c commandGetFloatv) hasIntRepresentation() bool {
   388      return false
   389  }
   390  
   391  func (c commandGetFloatv) hasFloatRepresentation() bool {
   392      return true
   393  }
   394  
   395  func (c commandGetFloatv) hasStringRepresentation() bool {
   396      return false
   397  }
   398  
   399  // ===[ commandGetString ]======================================================================[ commandGetString ]===
   400  
   401  type commandGetString struct {
   402      name string
   403  }
   404  
   405  func (c commandGetString) evalBool(b *Binding, e Extensions) bool {
   406      panic("not a bool")
   407  }
   408  
   409  func (c commandGetString) evalInt(b *Binding, e Extensions) int {
   410      panic("not an int")
   411  }
   412  
   413  func (c commandGetString) evalFloat(b *Binding, e Extensions) float32 {
   414      panic("not a float")
   415  }
   416  
   417  func (c commandGetString) evalString(b *Binding, e Extensions) string {
   418      var id, exists = glconstants[c.name]
   419      if !exists { return "" }
   420      return b.GetString(id)
   421  }
   422  
   423  func (c commandGetString) hasBoolRepresentation() bool {
   424      return false
   425  }
   426  
   427  func (c commandGetString) hasIntRepresentation() bool {
   428      return false
   429  }
   430  
   431  func (c commandGetString) hasFloatRepresentation() bool {
   432      return false
   433  }
   434  
   435  func (c commandGetString) hasStringRepresentation() bool {
   436      return true
   437  }
   438  
   439  // ===[ commandIf ]====================================================================================[ commandIf ]===
   440  
   441  type commandIf struct {
   442      clause command
   443      implication command
   444      otherwise command
   445  }
   446  
   447  func (c commandIf) evalBool(b *Binding, e Extensions) bool {
   448      if !c.hasBoolRepresentation() { panic(fmt.Sprintf("both clauses of %+v must have a bool representation", c)) }
   449      if c.clause.evalBool(b, e) {
   450          return c.implication.evalBool(b, e)
   451      } else {
   452          return c.otherwise.evalBool(b, e)
   453      }
   454  }
   455  
   456  func (c commandIf) evalInt(b *Binding, e Extensions) int {
   457      if !c.hasIntRepresentation() { panic(fmt.Sprintf("both clauses of %+v must have an int representation", c)) }
   458      if c.clause.evalBool(b, e) {
   459          return c.implication.evalInt(b, e)
   460      } else {
   461          return c.otherwise.evalInt(b, e)
   462      }
   463  }
   464  
   465  func (c commandIf) evalFloat(b *Binding, e Extensions) float32 {
   466      if !c.hasFloatRepresentation() { panic(fmt.Sprintf("both clauses of %+v must have an int representation", c)) }
   467      if c.clause.evalBool(b, e) {
   468          return c.implication.evalFloat(b, e)
   469      } else {
   470          return c.otherwise.evalFloat(b, e)
   471      }
   472  }
   473  
   474  func (c commandIf) evalString(b *Binding, e Extensions) string {
   475      if !c.hasStringRepresentation() { panic(fmt.Sprintf("both clauses of %+v must have a string representation", c)) }
   476      if c.clause.evalBool(b, e) {
   477          return c.implication.evalString(b, e)
   478      } else {
   479          return c.otherwise.evalString(b, e)
   480      }
   481  }
   482  
   483  func (c commandIf) hasBoolRepresentation() bool {
   484      return c.implication.hasBoolRepresentation() && c.otherwise.hasBoolRepresentation()
   485  }
   486  
   487  func (c commandIf) hasIntRepresentation() bool {
   488      return c.implication.hasIntRepresentation() && c.otherwise.hasIntRepresentation()
   489  }
   490  
   491  func (c commandIf) hasFloatRepresentation() bool {
   492      return c.implication.hasFloatRepresentation() && c.otherwise.hasFloatRepresentation()
   493  }
   494  
   495  func (c commandIf) hasStringRepresentation() bool {
   496      return c.implication.hasStringRepresentation() && c.otherwise.hasStringRepresentation()
   497  }
   498  

View as plain text