Untested analysis of switch statements

This commit is contained in:
Sasha Koshka 2024-03-25 12:08:28 -04:00
parent 6916b3b7b1
commit a50a5febb9
4 changed files with 101 additions and 1 deletions

View File

@ -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
// ordered.
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
// type.
func inRange (ty entity.Type, value int64) bool {

View File

@ -46,6 +46,8 @@ func (this *Tree) analyzeExpression (
return this.analyzeIfElse(into, mode, expression)
case *entity.Match:
return this.analyzeMatch(into, mode, expression)
case *entity.Switch:
return this.analyzeSwitch(into, mode, expression)
case *entity.Loop:
return this.analyzeLoop(into, mode, expression)
case *entity.For:

View File

@ -803,6 +803,87 @@ func (this *Tree) assembleMatchMap (match *entity.Match) (*entity.Match, error)
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 (
into entity.Type,
mode strictness,

View File

@ -459,7 +459,7 @@ type Switch struct {
// Semantics
Ty Type
CaseOrder []int64
CaseMap map[uint64] *MatchCase
CaseMap map[int64] *SwitchCase
}
func (*Switch) expression(){}
func (this *Switch) Position () errors.Position { return this.Pos }