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…
Reference in New Issue
Block a user