github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/compiler/analyzer/const.go (about) 1 package analyzer 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/nevalang/neva/internal/compiler" 8 src "github.com/nevalang/neva/internal/compiler/sourcecode" 9 ) 10 11 var ( 12 ErrEmptyConst = errors.New("Constant must either have value or reference to another constant") 13 ErrEntityNotConst = errors.New("Constant refers to an entity that is not constant") 14 ErrResolveConstType = errors.New("Cannot resolve constant type") 15 ErrUnionConst = errors.New("Constant cannot have type union") 16 ErrConstSeveralValues = errors.New("Constant cannot have several values at once") 17 ) 18 19 //nolint:funlen 20 func (a Analyzer) analyzeConst( 21 constant src.Const, 22 scope src.Scope, 23 ) (src.Const, *compiler.Error) { 24 if constant.Message == nil && constant.Ref == nil { 25 return src.Const{}, &compiler.Error{ 26 Err: ErrEmptyConst, 27 Location: &scope.Location, 28 Meta: &constant.Meta, 29 } 30 } 31 32 if constant.Message == nil { // is ref 33 entity, location, err := scope.Entity(*constant.Ref) 34 if err != nil { 35 return src.Const{}, &compiler.Error{ 36 Err: err, 37 Location: &location, 38 Meta: entity.Meta(), 39 } 40 } 41 42 if entity.Kind != src.ConstEntity { 43 return src.Const{}, &compiler.Error{ 44 Err: fmt.Errorf("%w: entity kind %v", ErrEntityNotConst, entity.Kind), 45 Location: &location, 46 Meta: entity.Meta(), 47 } 48 } 49 50 return a.analyzeConst(entity.Const, scope) 51 } 52 53 resolvedType, err := a.analyzeTypeExpr(constant.Message.TypeExpr, scope) 54 if err != nil { 55 return src.Const{}, compiler.Error{ 56 Err: ErrResolveConstType, 57 Location: &scope.Location, 58 Meta: &constant.Meta, 59 }.Wrap(err) 60 } 61 62 if resolvedType.Lit != nil && resolvedType.Lit.Union != nil { 63 return src.Const{}, &compiler.Error{ 64 Err: ErrUnionConst, 65 Location: &scope.Location, 66 Meta: &constant.Meta, 67 } 68 } 69 70 var typeExprStrRepr string 71 if inst := resolvedType.Inst; inst != nil { 72 typeExprStrRepr = inst.Ref.String() 73 } else if lit := resolvedType.Lit; lit != nil { 74 if lit.Enum != nil { 75 typeExprStrRepr = "enum" 76 } else if lit.Struct != nil { 77 typeExprStrRepr = "struct" 78 } 79 } 80 81 switch typeExprStrRepr { 82 case "bool": 83 if constant.Message.Bool == nil { 84 return src.Const{}, &compiler.Error{ 85 Err: fmt.Errorf("Boolean value is missing in boolean contant: %v", constant), 86 Location: &scope.Location, 87 Meta: &constant.Meta, 88 } 89 } 90 if constant.Message.Int != nil || 91 constant.Message.Float != nil || 92 constant.Message.Str != nil || 93 constant.Message.List != nil || 94 constant.Message.MapOrStruct != nil || 95 constant.Message.Enum != nil { 96 return src.Const{}, &compiler.Error{ 97 Err: fmt.Errorf("%w: %v", ErrConstSeveralValues, constant), 98 Location: &scope.Location, 99 Meta: &constant.Meta, 100 } 101 } 102 case "int": 103 if constant.Message.Int == nil { 104 return src.Const{}, &compiler.Error{ 105 Err: fmt.Errorf("Integer value is missing in integer contant: %v", constant), 106 Location: &scope.Location, 107 Meta: &constant.Meta, 108 } 109 } 110 if constant.Message.Bool != nil || 111 constant.Message.Float != nil || 112 constant.Message.Str != nil || 113 constant.Message.List != nil || 114 constant.Message.MapOrStruct != nil || 115 constant.Message.Enum != nil { 116 return src.Const{}, &compiler.Error{ 117 Err: fmt.Errorf("%w: %v", ErrConstSeveralValues, constant.Message), 118 Location: &scope.Location, 119 Meta: &constant.Meta, 120 } 121 } 122 case "float": 123 // Float is special case. Constant can have float type expression but integer literal. 124 // We must pass this case. Desugarer will turn integer literal into float. 125 if constant.Message.Float == nil && constant.Message.Int == nil { 126 return src.Const{}, &compiler.Error{ 127 Err: fmt.Errorf("Float or integer value is missing in float contant: %v", constant), 128 Location: &scope.Location, 129 Meta: &constant.Meta, 130 } 131 } 132 if constant.Message.Float != nil && constant.Message.Int != nil { 133 return src.Const{}, &compiler.Error{ 134 Err: fmt.Errorf("%w: %v", ErrConstSeveralValues, constant.Message), 135 Location: &scope.Location, 136 Meta: &constant.Meta, 137 } 138 } 139 if constant.Message.Bool != nil || 140 constant.Message.Str != nil || 141 constant.Message.List != nil || 142 constant.Message.MapOrStruct != nil || 143 constant.Message.Enum != nil { 144 return src.Const{}, &compiler.Error{ 145 Err: fmt.Errorf("%w: %v", ErrConstSeveralValues, constant.Message), 146 Location: &scope.Location, 147 Meta: &constant.Meta, 148 } 149 } 150 case "string": 151 if constant.Message.Str == nil { 152 return src.Const{}, &compiler.Error{ 153 Err: fmt.Errorf("String value is missing in string contant: %v", constant), 154 Location: &scope.Location, 155 Meta: &constant.Meta, 156 } 157 } 158 if constant.Message.Bool != nil || 159 constant.Message.Int != nil || 160 constant.Message.Float != nil || 161 constant.Message.List != nil || 162 constant.Message.MapOrStruct != nil || 163 constant.Message.Enum != nil { 164 return src.Const{}, &compiler.Error{ 165 Err: fmt.Errorf("%w: %v", ErrConstSeveralValues, constant.Message), 166 Location: &scope.Location, 167 Meta: &constant.Meta, 168 } 169 } 170 case "list": 171 if constant.Message.List == nil { 172 return src.Const{}, &compiler.Error{ 173 Err: fmt.Errorf("List value is missing in list contant: %v", constant), 174 Location: &scope.Location, 175 Meta: &constant.Meta, 176 } 177 } 178 if constant.Message.Bool != nil || 179 constant.Message.Int != nil || 180 constant.Message.Float != nil || 181 constant.Message.MapOrStruct != nil || 182 constant.Message.Enum != nil { 183 return src.Const{}, &compiler.Error{ 184 Err: fmt.Errorf("%w: %v", ErrConstSeveralValues, constant.Message), 185 Location: &scope.Location, 186 Meta: &constant.Meta, 187 } 188 } 189 case "map", "struct": 190 if constant.Message.MapOrStruct == nil { 191 return src.Const{}, &compiler.Error{ 192 Err: fmt.Errorf("Map or struct value is missing in map or struct contant: %v", constant), 193 Location: &scope.Location, 194 Meta: &constant.Meta, 195 } 196 } 197 if constant.Message.Bool != nil || 198 constant.Message.Int != nil || 199 constant.Message.Float != nil || 200 constant.Message.List != nil || 201 constant.Message.Enum != nil { 202 return src.Const{}, &compiler.Error{ 203 Err: fmt.Errorf("%w: %v", ErrConstSeveralValues, constant.Message), 204 Location: &scope.Location, 205 Meta: &constant.Meta, 206 } 207 } 208 case "enum": 209 if constant.Message.Enum == nil { 210 return src.Const{}, &compiler.Error{ 211 Err: fmt.Errorf("Enum value is missing in enum contant: %v", constant), 212 Location: &scope.Location, 213 Meta: &constant.Meta, 214 } 215 } 216 if constant.Message.Bool != nil || 217 constant.Message.Int != nil || 218 constant.Message.Float != nil || 219 constant.Message.List != nil || 220 constant.Message.MapOrStruct != nil { 221 return src.Const{}, &compiler.Error{ 222 Err: fmt.Errorf("%w: %v", ErrConstSeveralValues, constant.Message), 223 Location: &scope.Location, 224 Meta: &constant.Meta, 225 } 226 } 227 } 228 229 valueCopy := *constant.Message 230 valueCopy.TypeExpr = resolvedType 231 232 return src.Const{ 233 Message: &valueCopy, 234 Meta: constant.Meta, 235 }, nil 236 }