Untested analysis of switch statements
This commit is contained in:
		
							parent
							
								
									6916b3b7b1
								
							
						
					
					
						commit
						a50a5febb9
					
				@ -483,6 +483,14 @@ func isInteger (ty entity.Type) bool {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// isPointer returns whether or not the specified type is a pointer.
 | 
				
			||||||
 | 
					func isPointer (ty entity.Type) bool {
 | 
				
			||||||
 | 
						switch ReduceToBase(ty).(type) {
 | 
				
			||||||
 | 
						case *entity.TypePointer: return true
 | 
				
			||||||
 | 
						default: return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// isOrdered returns whether or not the values of the specified type can be
 | 
					// isOrdered returns whether or not the values of the specified type can be
 | 
				
			||||||
// ordered.
 | 
					// ordered.
 | 
				
			||||||
func isOrdered (ty entity.Type) bool {
 | 
					func isOrdered (ty entity.Type) bool {
 | 
				
			||||||
@ -515,6 +523,15 @@ func IsUnsigned (ty entity.Type) bool {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// integerWidth returns the width of the type, if it is an integer.
 | 
				
			||||||
 | 
					func integerWidth (ty entity.Type) (int, bool) {
 | 
				
			||||||
 | 
						switch ty := ReduceToBase(ty).(type) {
 | 
				
			||||||
 | 
						case *entity.TypeInt: return ty.Width, true
 | 
				
			||||||
 | 
						default: return 0, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// inRange returns whether the specified value can fit within the given integer
 | 
					// inRange returns whether the specified value can fit within the given integer
 | 
				
			||||||
// type.
 | 
					// type.
 | 
				
			||||||
func inRange (ty entity.Type, value int64) bool {
 | 
					func inRange (ty entity.Type, value int64) bool {
 | 
				
			||||||
 | 
				
			|||||||
@ -46,6 +46,8 @@ func (this *Tree) analyzeExpression (
 | 
				
			|||||||
		return this.analyzeIfElse(into, mode, expression)
 | 
							return this.analyzeIfElse(into, mode, expression)
 | 
				
			||||||
	case *entity.Match:
 | 
						case *entity.Match:
 | 
				
			||||||
		return this.analyzeMatch(into, mode, expression)
 | 
							return this.analyzeMatch(into, mode, expression)
 | 
				
			||||||
 | 
						case *entity.Switch:
 | 
				
			||||||
 | 
							return this.analyzeSwitch(into, mode, expression)
 | 
				
			||||||
	case *entity.Loop:
 | 
						case *entity.Loop:
 | 
				
			||||||
		return this.analyzeLoop(into, mode, expression)
 | 
							return this.analyzeLoop(into, mode, expression)
 | 
				
			||||||
	case *entity.For:
 | 
						case *entity.For:
 | 
				
			||||||
 | 
				
			|||||||
@ -803,6 +803,87 @@ func (this *Tree) assembleMatchMap (match *entity.Match) (*entity.Match, error)
 | 
				
			|||||||
	return match, nil
 | 
						return match, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *Tree) analyzeSwitch (
 | 
				
			||||||
 | 
						into  entity.Type,
 | 
				
			||||||
 | 
						mode  strictness,
 | 
				
			||||||
 | 
						switc *entity.Switch,
 | 
				
			||||||
 | 
					) (
 | 
				
			||||||
 | 
						entity.Expression,
 | 
				
			||||||
 | 
						error,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
						value, err := this.analyzeExpression(nil, strict, switc.Value)
 | 
				
			||||||
 | 
						if err != nil { return nil, err }
 | 
				
			||||||
 | 
						switc.Value = value
 | 
				
			||||||
 | 
						width, integerOk := integerWidth(value.Type())
 | 
				
			||||||
 | 
						if !integerOk {
 | 
				
			||||||
 | 
							return nil, errors.Errorf (
 | 
				
			||||||
 | 
								value.Position(), "cannot switch on type %v",
 | 
				
			||||||
 | 
								value.Type())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switc.CaseOrder = make([]int64, len(switc.Cases))
 | 
				
			||||||
 | 
						switc.CaseMap   = make(map[int64] *entity.SwitchCase)
 | 
				
			||||||
 | 
						for index, cas := range switc.Cases {
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							this.pushScope(cas)
 | 
				
			||||||
 | 
								key, err := this.analyzeExpression (
 | 
				
			||||||
 | 
									value.Type(), strict,
 | 
				
			||||||
 | 
									cas.Key)
 | 
				
			||||||
 | 
								if err != nil { this.popScope(); return nil, err }
 | 
				
			||||||
 | 
								cas.Key = key
 | 
				
			||||||
 | 
								expression, err := this.analyzeExpression (
 | 
				
			||||||
 | 
									into, mode,
 | 
				
			||||||
 | 
									cas.Expression)
 | 
				
			||||||
 | 
								if err != nil { this.popScope(); return nil, err }
 | 
				
			||||||
 | 
								cas.Expression = expression
 | 
				
			||||||
 | 
							this.popScope()
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var keyInt int64
 | 
				
			||||||
 | 
							switch key := key.(type) {
 | 
				
			||||||
 | 
							case *entity.LiteralInt:
 | 
				
			||||||
 | 
								keyInt = int64(key.Value)
 | 
				
			||||||
 | 
							case *entity.LiteralString:
 | 
				
			||||||
 | 
								switch {
 | 
				
			||||||
 | 
								case width >= 32:
 | 
				
			||||||
 | 
									keyInt = int64(key.ValueUTF32[0])
 | 
				
			||||||
 | 
								case width >= 16:
 | 
				
			||||||
 | 
									keyInt = int64(key.ValueUTF16[0])
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									keyInt = int64(key.ValueUTF8[0])
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
							return nil, errors.Errorf (
 | 
				
			||||||
 | 
								key.Position(), "%v cannot represent a constant integer",
 | 
				
			||||||
 | 
								key)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							switc.Cases[index]     = cas
 | 
				
			||||||
 | 
							switc.CaseMap[keyInt]  = cas
 | 
				
			||||||
 | 
							switc.CaseOrder[index] = keyInt
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if switc.Default != nil {
 | 
				
			||||||
 | 
							this.pushScope(switc.Default)
 | 
				
			||||||
 | 
							expression, err := this.analyzeExpression (
 | 
				
			||||||
 | 
								into, mode,
 | 
				
			||||||
 | 
								switc.Default.Expression)
 | 
				
			||||||
 | 
							this.popScope()
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if err != nil { return nil, err }
 | 
				
			||||||
 | 
							switc.Default.Expression = expression
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if into != nil && switc.Default != nil {
 | 
				
			||||||
 | 
							return nil, errors.Errorf (
 | 
				
			||||||
 | 
								switc.Position(),
 | 
				
			||||||
 | 
								"switch must have a default case")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switc.Ty = into
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return switc, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *Tree) analyzeLoop (
 | 
					func (this *Tree) analyzeLoop (
 | 
				
			||||||
	into entity.Type,
 | 
						into entity.Type,
 | 
				
			||||||
	mode strictness,
 | 
						mode strictness,
 | 
				
			||||||
 | 
				
			|||||||
@ -459,7 +459,7 @@ type Switch struct {
 | 
				
			|||||||
	// Semantics
 | 
						// Semantics
 | 
				
			||||||
	Ty        Type
 | 
						Ty        Type
 | 
				
			||||||
	CaseOrder []int64
 | 
						CaseOrder []int64
 | 
				
			||||||
	CaseMap   map[uint64] *MatchCase
 | 
						CaseMap   map[int64] *SwitchCase
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (*Switch) expression(){}
 | 
					func (*Switch) expression(){}
 | 
				
			||||||
func (this *Switch) Position () errors.Position { return this.Pos }
 | 
					func (this *Switch) Position () errors.Position { return this.Pos }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user