fspl/analyzer/literal.go

298 lines
6.8 KiB
Go
Raw Normal View History

2023-10-27 20:10:31 +00:00
package analyzer
2023-11-26 22:27:09 +00:00
import "unicode/utf16"
2024-02-23 00:22:53 +00:00
import "git.tebibyte.media/fspl/fspl/errors"
import "git.tebibyte.media/fspl/fspl/entity"
2023-10-27 20:10:31 +00:00
func (this *Tree) analyzeLiteralInt (
into entity.Type,
mode strictness,
literal *entity.LiteralInt,
) (
entity.Expression,
error,
) {
2024-03-14 07:18:46 +00:00
err := this.typeOpaque(literal.Position(), into)
if err != nil { return nil, err }
2023-11-21 20:04:01 +00:00
if !isNumeric(into) {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(), "cannot use integer literal as %v",
entity.FormatType(into))
2023-10-27 20:10:31 +00:00
}
2023-11-21 20:04:01 +00:00
if isInteger(into) && !inRange(into, int64(literal.Value)) {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(), "integer literal out of range for type %v",
entity.FormatType(into))
2023-10-27 20:10:31 +00:00
}
literal.Ty = into
return literal, nil
}
func (this *Tree) analyzeLiteralFloat (
into entity.Type,
mode strictness,
literal *entity.LiteralFloat,
) (
entity.Expression,
error,
) {
2024-03-14 07:18:46 +00:00
err := this.typeOpaque(literal.Position(), into)
if err != nil { return nil, err }
2023-11-21 20:04:01 +00:00
if !isFloat(into) {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(), "cannot use float literal as %v",
entity.FormatType(into))
2023-10-27 20:10:31 +00:00
}
literal.Ty = into
return literal, nil
}
2023-11-26 22:27:09 +00:00
func (this *Tree) analyzeLiteralString (
into entity.Type,
mode strictness,
literal *entity.LiteralString,
) (
entity.Expression,
error,
) {
2024-03-14 07:18:46 +00:00
err := this.typeOpaque(literal.Position(), into)
if err != nil { return nil, err }
2023-11-26 22:27:09 +00:00
base := ReduceToBase(into)
errCantUse := func () error {
2024-02-08 08:51:21 +00:00
return errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(), "cannot use string literal as %v",
entity.FormatType(into))
2023-11-26 22:27:09 +00:00
}
fillUTF32 := func () {
literal.ValueUTF32 = []rune(literal.ValueUTF8)
}
fillUTF16 := func () {
literal.ValueUTF16 = utf16.Encode([]rune(literal.ValueUTF8))
}
switch base := base.(type) {
case *entity.TypeInt:
var length int; switch {
case base.Width >= 32:
fillUTF32()
length = len(literal.ValueUTF32)
case base.Width >= 16:
fillUTF16()
length = len(literal.ValueUTF16)
default:
length = len(literal.ValueUTF8)
}
if length > 1 {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(),
2023-11-26 22:27:09 +00:00
"cannot fit string literal of length " +
"%v into %v",
length, entity.FormatType(into))
2023-11-26 22:27:09 +00:00
} else if length < 1 {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(),
2023-11-26 22:27:09 +00:00
"string literal must have data when " +
"assigning to %v",
entity.FormatType(into))
2023-11-26 22:27:09 +00:00
}
case *entity.TypeArray:
element := ReduceToBase(base.Element)
if element, ok := element.(*entity.TypeInt); ok {
2023-11-26 22:27:09 +00:00
var length int; switch {
case element.Width >= 32:
fillUTF32()
length = len(literal.ValueUTF32)
case element.Width >= 16:
fillUTF16()
length = len(literal.ValueUTF16)
default:
length = len(literal.ValueUTF8)
}
if length > base.Length {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(),
2023-11-26 22:27:09 +00:00
"cannot fit string literal of length " +
"%v into array of length %v",
length, base.Length)
}
} else {
return nil, errCantUse()
}
case *entity.TypeSlice:
element := ReduceToBase(base.Element)
if element, ok := element.(*entity.TypeInt); ok {
2023-11-26 22:27:09 +00:00
if element.Width >= 32 {
fillUTF32()
} else if element.Width >= 16 {
fillUTF16()
}
} else {
return nil, errCantUse()
}
case *entity.TypePointer:
referenced := ReduceToBase(base.Referenced)
if referenced, ok := referenced.(*entity.TypeInt); ok {
if referenced.Width != 8 {
return nil, errCantUse()
}
} else {
return nil, errCantUse()
}
default:
return nil, errCantUse()
}
literal.Ty = into
return literal, nil
}
2023-10-27 20:10:31 +00:00
func (this *Tree) analyzeLiteralArray (
into entity.Type,
mode strictness,
literal *entity.LiteralArray,
) (
entity.Expression,
error,
) {
2024-03-14 07:18:46 +00:00
err := this.typeOpaque(literal.Position(), into)
if err != nil { return nil, err }
2023-11-21 20:04:01 +00:00
base := ReduceToBase(into)
var elementType entity.Type
2023-10-29 19:18:44 +00:00
switch base.(type) {
case *entity.TypeArray:
2023-10-29 19:18:44 +00:00
base := base.(*entity.TypeArray)
if base.Length < len(literal.Elements) {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(), "expected %v elements or less",
2023-10-29 19:18:44 +00:00
base.Length)
}
2023-10-29 19:18:44 +00:00
elementType = base.Element
case *entity.TypeSlice:
2023-10-29 19:18:44 +00:00
base := base.(*entity.TypeSlice)
elementType = base.Element
2023-11-21 20:04:01 +00:00
case *entity.TypePointer:
base := base.(*entity.TypePointer)
elementType = base.Referenced
default:
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(), "cannot use array literal as %v",
entity.FormatType(into))
2023-10-27 20:10:31 +00:00
}
for index, element := range literal.Elements {
element, err := this.analyzeExpression(elementType, strict, element)
2023-10-27 20:10:31 +00:00
if err != nil { return nil, err }
literal.Elements[index] = element
}
literal.Ty = into
return literal, nil
}
2023-10-28 07:24:17 +00:00
func (this *Tree) analyzeLiteralStruct (
into entity.Type,
mode strictness,
literal *entity.LiteralStruct,
) (
entity.Expression,
error,
) {
2024-03-14 07:18:46 +00:00
err := this.typeOpaque(literal.Position(), into)
if err != nil { return nil, err }
2023-11-21 20:04:01 +00:00
base, ok := ReduceToBase(into).(*entity.TypeStruct)
2023-10-28 07:24:17 +00:00
if !ok {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(), "cannot use struct literal as %v",
entity.FormatType(into))
2023-10-28 07:24:17 +00:00
}
literal, err = this.assembleStructLiteralMap(literal)
2023-10-28 07:24:17 +00:00
if err != nil { return nil, err }
for name, member := range literal.MemberMap {
correct, ok := base.MemberMap[name]
if !ok {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(), "no member %v.%s",
2023-10-28 07:24:17 +00:00
into, name)
}
value, err := this.analyzeExpression(correct.Type(), strict, member.Value)
if err != nil { return nil, err }
member.Value = value
}
literal.Ty = into
return literal, nil
}
func (this *Tree) analyzeLiteralBoolean (
into entity.Type,
mode strictness,
literal *entity.LiteralBoolean,
) (
entity.Expression,
error,
) {
2024-03-14 07:18:46 +00:00
err := this.typeOpaque(literal.Position(), into)
if err != nil { return nil, err }
2023-11-21 20:04:01 +00:00
if !isBoolean(into) {
2024-02-08 08:51:21 +00:00
return nil, errors.Errorf (
2024-03-14 07:18:46 +00:00
literal.Position(), "cannot use boolean literal as %v",
entity.FormatType(into))
2023-10-28 07:24:17 +00:00
}
literal.Ty = into
return literal, nil
}
2023-12-22 04:33:38 +00:00
func (this *Tree) analyzeLiteralNil (
into entity.Type,
mode strictness,
literal *entity.LiteralNil,
) (
entity.Expression,
error,
) {
2024-03-14 07:18:46 +00:00
err := this.typeOpaque(literal.Position(), into)
if err != nil { return nil, err }
2023-12-22 04:33:38 +00:00
literal.Ty = into
return literal, nil
}
2023-10-28 07:24:17 +00:00
func (this *Tree) assembleStructLiteralMap (
literal *entity.LiteralStruct,
) (
*entity.LiteralStruct,
error,
) {
literal.MemberMap = make(map[string] *entity.Member)
literal.MemberOrder = make([]string, len(literal.Members))
for index, member := range literal.Members {
if previous, exists := literal.MemberMap[member.Name]; exists {
2024-02-08 08:51:21 +00:00
return literal, errors.Errorf (
2024-03-14 07:18:46 +00:00
member.Position(), "%s already listed in struct literal at %v",
member.Name, previous.Position())
2023-10-28 07:24:17 +00:00
}
literal.MemberMap [member.Name] = member
literal.MemberOrder[index] = member.Name
literal.Members [index] = member
}
return literal, nil
}