Start analyzing literals

This commit is contained in:
Sasha Koshka 2023-10-27 16:10:31 -04:00
parent c88ba16bdc
commit a6fec780c7
3 changed files with 133 additions and 1 deletions

View File

@ -1,9 +1,11 @@
package analyzer
import "fmt"
import "math"
import "github.com/alecthomas/participle/v2"
import "github.com/alecthomas/participle/v2/lexer"
import "git.tebibyte.media/sashakoshka/fspl/entity"
import "git.tebibyte.media/sashakoshka/fspl/integer"
type strictness int; const (
// name equivalence
@ -304,3 +306,45 @@ func (this *Tree) isBoolean (ty entity.Type) bool {
default: return false
}
}
// isFloat returns whether or not the specified type is a float.
func (this *Tree) isFloat (ty entity.Type) bool {
switch this.reduceToBase(ty).(type) {
case *entity.TypeFloat: return true
default: return false
}
}
// isUnsigned returns whether or not the specified type is an unsigned integer.
func (this *Tree) isUnsigned (ty entity.Type) bool {
switch this.reduceToBase(ty).(type) {
case *entity.TypeInt: return ty.(*entity.TypeInt).Signed
case *entity.TypeWord: return ty.(*entity.TypeInt).Signed
default: return false
}
}
// inRange returns whether the specified value can fit within the given integer
// type.
func (this *Tree) inRange (ty entity.Type, value int64) bool {
base := this.reduceToBase(ty)
switch base.(type) {
case *entity.TypeInt:
base := base.(*entity.TypeInt)
if base.Signed {
return value > integer.SignedMin(base.Width) &&
value < integer.SignedMax(base.Width)
} else {
return value > 0 &&
uint64(value) < integer.UnsignedMax(base.Width)
}
case *entity.TypeWord:
base := base.(*entity.TypeWord)
if base.Signed {
return value > math.MinInt && value < math.MaxInt
} else {
return value > 0 && uint64(value) < math.MaxUint
}
default: return false
}
}

View File

@ -46,7 +46,17 @@ func (this *Tree) analyzeExpression (
// return this.analyzeBreak(into, mode, expression.(*entity.Break))
// case *entity.Return:
// return this.analyzeReturn(into, mode, expression.(*entity.Return))
// TODO literals
case *entity.LiteralInt:
return this.analyzeLiteralInt(into, mode, expression.(*entity.LiteralInt))
case *entity.LiteralFloat:
return this.analyzeLiteralFloat(into, mode, expression.(*entity.LiteralFloat))
case *entity.LiteralArray:
return this.analyzeLiteralArray(into, mode, expression.(*entity.LiteralArray))
case *entity.LiteralStruct:
return this.analyzeLiteralStruct(into, mode, expression.(*entity.LiteralStruct))
case *entity.LiteralBoolean:
return this.analyzeLiteralBoolean(into, mode, expression.(*entity.LiteralBoolean))
default:
panic(fmt.Sprint (
"BUG: analyzer doesnt know about expression ",

78
analyzer/literal.go Normal file
View File

@ -0,0 +1,78 @@
package analyzer
// import "fmt"
import "github.com/alecthomas/participle/v2"
import "git.tebibyte.media/sashakoshka/fspl/entity"
func (this *Tree) analyzeLiteralInt (
into entity.Type,
mode strictness,
literal *entity.LiteralInt,
) (
entity.Expression,
error,
) {
if !this.isNumeric(into) {
return nil, participle.Errorf (
literal.Pos, "cannot use integer literal as %v",
into)
}
if this.isInteger(into) && !this.inRange(into, int64(literal.Value)) {
return nil, participle.Errorf (
literal.Pos, "integer literal out of range for type %v",
into)
}
literal.Ty = into
return literal, nil
}
func (this *Tree) analyzeLiteralFloat (
into entity.Type,
mode strictness,
literal *entity.LiteralFloat,
) (
entity.Expression,
error,
) {
if !this.isFloat(into) {
return nil, participle.Errorf (
literal.Pos, "cannot use float literal as %v",
into)
}
literal.Ty = into
return literal, nil
}
func (this *Tree) analyzeLiteralArray (
into entity.Type,
mode strictness,
literal *entity.LiteralArray,
) (
entity.Expression,
error,
) {
base, ok := this.reduceToBase(into).(*entity.TypeArray)
if !ok {
return nil, participle.Errorf (
literal.Pos, "cannot use array literal as %v",
into)
}
if base.Length != len(literal.Elements) {
return nil, participle.Errorf (
literal.Pos, "expected %v elements",
base.Length)
}
for index, element := range literal.Elements {
element, err := this.analyzeExpression(base.Element, strict, element)
if err != nil { return nil, err }
literal.Elements[index] = element
}
literal.Ty = into
return literal, nil
}