1// ================================================================ 2// The `types.Mlrval` structure includes **string, int, float, boolean, void, 3// absent, and error** types (not unlike PHP's `zval`) as well as 4// type-conversion logic for various operators. 5// 6// Whenever I say "int" and "float" with regard to mlrvals I always mean 7// "int" and "float64". If I ever miss a spot and use Go int/float types then 8// that is a bug. It would be great to be able to somehow lint for this. 9// ================================================================ 10 11package types 12 13type Mlrval struct { 14 15 // Enumeration for string / int / float / boolean / etc. 16 // I would call this "type" not "mvtype" but "type" is a keyword in Go. 17 mvtype MVType 18 19 // An int/float always starts from a string -- be it from record data from 20 // a file, or a literal within a DSL expression. The printrep is exactly 21 // that string, however the user formatted it, and the intval/floatval is 22 // computed from that -- and in sync with it -- at construction time. 23 // 24 // When a mlrval is computed from one or more others -- e.g. '$z = $x + 4' 25 // -- the printrep is not updated. That would be wasted CPU, since the 26 // string representation is not needed until when/if the value is printed 27 // as output. For computation methods the printrep is neglected and the 28 // printrepValid is set to false. 29 // 30 // In the String() method the printrep is computed from the intval/floatval 31 // and printrepValid is set back to true. 32 // 33 // Note that for MT_STRING, the printrep is always valid since it is the 34 // only payload for the mlrval. 35 // 36 // Thus we (a) keep user-specific input-formatting when possible, for the 37 // principle of least surprise; (b) avoid reformatting strings during 38 // intermediate arithmetic expressions; (c) resync arithmetic results to 39 // string formatting on a just-in-time basis when output is printed. 40 printrep string 41 printrepValid bool 42 intval int 43 floatval float64 44 boolval bool 45 arrayval []Mlrval 46 mapval *Mlrmap 47} 48 49// Enumeration for mlrval types 50// 51// There are two kinds of null: ABSENT (key not present in a record) and VOID 52// (key present with empty value). Note void is an acceptable string (empty 53// string) but not an acceptable number. (In Javascript, similarly, there are 54// undefined and null, respectively.) 55 56type MVType int 57 58// Important: the values of these enums are used to index into disposition 59// matrices. If they are changed, it will break the disposition matrices, or 60// they will all need manual re-indexing. 61const ( 62 // Type not yet determined, during JSON decode. 63 MT_PENDING MVType = -1 64 65 // E.g. error encountered in one eval & it propagates up the AST at 66 // evaluation time. Various runtime errors, such as file-not-found, result 67 // in a message to stderr and os.Exit(1). But errors in user-provided data 68 // are intended to result in "(error)"-valued output rather than a crash. 69 // This is analogous to the way that IEEE-754 arithmetic carries around 70 // Inf and NaN through computation chains. 71 MT_ERROR = 0 72 73 // Key not present in input record, e.g. 'foo = $nosuchkey' 74 MT_ABSENT = 1 75 76 // Key present in input record with empty value, e.g. input data '$x=,$y=2' 77 MT_VOID = 2 78 79 MT_STRING = 3 80 81 MT_INT = 4 82 83 MT_FLOAT = 5 84 85 MT_BOOL = 6 86 87 MT_ARRAY = 7 88 89 MT_MAP = 8 90 91 // Not a type -- this is a dimension for disposition vectors and 92 // disposition matrices. For example, when we want to add two mlrvals, 93 // instead of if/elsing or switching on the types of both operands, we 94 // instead jump directly to a type-specific function in a matrix of 95 // function pointers which is MT_DIM x MT_DIM. 96 MT_DIM = 9 97) 98 99var TYPE_NAMES = [MT_DIM]string{ 100 "error", 101 "absent", 102 "empty", // For backward compatiblity with the C impl: this is user-visible 103 "string", 104 "int", 105 "float", 106 "bool", 107 "array", 108 "map", 109} 110 111// ---------------------------------------------------------------- 112// For typed assignments in the DSL 113 114// TODO: comment more re typedecls 115const MT_TYPE_MASK_STRING = (1 << MT_STRING) | (1 << MT_VOID) 116const MT_TYPE_MASK_INT = 1 << MT_INT 117const MT_TYPE_MASK_FLOAT = 1 << MT_FLOAT 118const MT_TYPE_MASK_NUM = (1 << MT_INT) | (1 << MT_FLOAT) 119const MT_TYPE_MASK_BOOL = 1 << MT_BOOL 120const MT_TYPE_MASK_ARRAY = 1 << MT_ARRAY 121const MT_TYPE_MASK_MAP = 1 << MT_MAP 122const MT_TYPE_MASK_VAR = (1 << MT_VOID) | (1 << MT_STRING) | (1 << MT_INT) | 123 (1 << MT_FLOAT) | (1 << MT_BOOL) | (1 << MT_ARRAY) | (1 << MT_MAP) 124 125// Not exposed in userspace 126const MT_TYPE_MASK_ANY = (1 << MT_ERROR) | (1 << MT_ABSENT) | MT_TYPE_MASK_VAR 127 128var typeNameToMaskMap = map[string]int{ 129 "var": MT_TYPE_MASK_VAR, 130 "str": MT_TYPE_MASK_STRING, 131 "int": MT_TYPE_MASK_INT, 132 "float": MT_TYPE_MASK_FLOAT, 133 "num": MT_TYPE_MASK_NUM, 134 "bool": MT_TYPE_MASK_BOOL, 135 "arr": MT_TYPE_MASK_ARRAY, 136 "map": MT_TYPE_MASK_MAP, 137 "any": MT_TYPE_MASK_ANY, 138} 139 140func TypeNameToMask(typeName string) (mask int, present bool) { 141 retval := typeNameToMaskMap[typeName] 142 if retval != 0 { 143 return retval, true 144 } else { 145 return 0, false 146 } 147} 148 149func (this *Mlrval) GetTypeBit() int { 150 return 1 << this.mvtype 151} 152