fspl/generator/literal.go

223 lines
6.7 KiB
Go

package generator
import "fmt"
import "errors"
import "git.tebibyte.media/sashakoshka/fspl/llvm"
import "git.tebibyte.media/sashakoshka/fspl/entity"
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
func (this *generator) generateLiteralInt (literal *entity.LiteralInt) (llvm.Value, error) {
irType, err := this.generateType(analyzer.ReduceToBase(literal.Type()))
if err != nil { return nil, err }
return llvm.NewConstInt(irType.(*llvm.TypeInt), int64(literal.Value)), nil
}
func (this *generator) generateLiteralFloat (literal *entity.LiteralFloat) (llvm.Value, error) {
irType, err := this.generateType(analyzer.ReduceToBase(literal.Type()))
if err != nil { return nil, err }
return llvm.NewConstFloat(irType.(*llvm.TypeFloat), literal.Value), nil
}
func (this *generator) generateLiteralArrayLoc (literal *entity.LiteralArray) (llvm.Value, error) {
ty := analyzer.ReduceToBase(literal.Type())
makeData := func (elementType entity.Type) (llvm.Value, error) {
irArrayType, err := this.generateType(&entity.TypeArray {
Element: elementType,
Length: len(literal.Elements),
})
if err != nil { return nil, err }
array := this.blockManager.newAllocaFront(irArrayType)
for index, element := range literal.Elements {
irElement, err := this.generateAssignmentSource (
element,
elementType)
if err != nil { return nil, err }
elementPointer := this.blockManager.NewGetElementPtr (
irArrayType, array,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, int64(index)))
this.blockManager.NewStore(irElement, elementPointer)
}
return array, nil
}
switch ty := ty.(type) {
case *entity.TypeArray:
return makeData(ty.Element)
case *entity.TypeSlice:
array, err := makeData(ty.Element)
if err != nil { return nil, err }
return this.generateSlice(ty, array, int64(len(literal.Elements)))
case *entity.TypePointer:
array, err := makeData(ty.Referenced)
if err != nil { return nil, err }
return this.valueToLocation(array), nil
default:
return nil, errors.New(fmt.Sprintln("array can't be used as ", ty))
}
}
func (this *generator) generateLiteralStringLoc (literal *entity.LiteralString) (llvm.Value, error) {
base := analyzer.ReduceToBase(literal.Type())
makeData := func (anyElementType entity.Type, cstring bool) (llvm.Value, int64, error) {
elementType, ok := analyzer.ReduceToBase(anyElementType).(*entity.TypeInt)
if !ok {
return nil, 0, errors.New(fmt.Sprintln("string can't be used as ", base))
}
switch {
case elementType.Width >= 32:
length := len(literal.ValueUTF32)
if cstring { length += 1 }
irArrayType, err := this.generateType(&entity.TypeArray {
Element: elementType,
Length: length,
})
if err != nil { return nil, 0, err }
array := this.blockManager.newAllocaFront(irArrayType)
for index := 0; index < length; index ++ {
var element int64
if index >= len(literal.ValueUTF32) {
element = 0
} else {
element = int64(literal.ValueUTF32[index])
}
elementPointer := this.blockManager.NewGetElementPtr (
irArrayType, array,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, int64(index)))
this.blockManager.NewStore (
llvm.NewConstInt(llvm.I32, element),
elementPointer)
}
return array, int64(length), nil
case elementType.Width >= 16:
length := len(literal.ValueUTF16)
if cstring { length += 1 }
irArrayType, err := this.generateType(&entity.TypeArray {
Element: elementType,
Length: length,
})
if err != nil { return nil, 0, err }
array := this.blockManager.newAllocaFront(irArrayType)
for index := 0; index < length; index ++ {
var element int64
if index >= len(literal.ValueUTF16) {
element = 0
} else {
element = int64(literal.ValueUTF16[index])
}
elementPointer := this.blockManager.NewGetElementPtr (
irArrayType, array,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, int64(index)))
this.blockManager.NewStore (
llvm.NewConstInt(llvm.I16, element),
elementPointer)
}
return array, int64(length), nil
default:
length := len(literal.ValueUTF8)
if cstring { length += 1 }
irArrayType, err := this.generateType(&entity.TypeArray {
Element: elementType,
Length: length,
})
if err != nil { return nil, 0, err }
array := this.blockManager.newAllocaFront(irArrayType)
for index := 0; index < length; index ++ {
var element int64
if index >= len(literal.ValueUTF8) {
element = 0
} else {
element = int64(literal.ValueUTF8[index])
}
elementPointer := this.blockManager.NewGetElementPtr (
irArrayType, array,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, int64(index)))
this.blockManager.NewStore (
llvm.NewConstInt(llvm.I8, element),
elementPointer)
}
return array, int64(length), nil
}
}
switch base := base.(type) {
case *entity.TypeInt:
var value llvm.Value
irType, err := this.generateType(base)
if err != nil { return nil, err }
switch {
case base.Width >= 32:
value = llvm.NewConstInt(llvm.I32, int64(literal.ValueUTF32[0]))
case base.Width >= 16:
value = llvm.NewConstInt(llvm.I16, int64(literal.ValueUTF16[0]))
default:
value = llvm.NewConstInt(llvm.I8, int64(literal.ValueUTF8[0]))
}
char := this.blockManager.newAllocaFront(irType)
this.blockManager.NewStore(value, char)
return char, nil
case *entity.TypeArray:
value, _, err := makeData(base.Element, false)
return value, err
case *entity.TypeSlice:
array, length, err := makeData(base.Element, false)
if err != nil { return nil, err }
return this.generateSlice(base, array, length)
case *entity.TypePointer:
array, _, err := makeData(base.Referenced, true)
if err != nil { return nil, err }
return this.valueToLocation(array), nil
default:
return nil, errors.New(fmt.Sprintln("string can't be used as ", base))
}
}
func (this *generator) generateLiteralStructLoc (literal *entity.LiteralStruct) (llvm.Value, error) {
ty := analyzer.ReduceToBase(literal.Type())
irType, err := this.generateType(ty)
if err != nil { return nil, err }
structure := this.blockManager.newAllocaFront(irType)
for index, member := range literal.Members {
irMember, err := this.generateExpression(member.Value)
if err != nil { return nil, err }
elementPointer := this.blockManager.NewGetElementPtr (
irType, structure,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, int64(index)))
this.blockManager.NewStore(irMember, elementPointer)
}
return structure, nil
}
func (this *generator) generateLiteralBoolean (literal *entity.LiteralBoolean) (llvm.Value, error) {
return llvm.NewConstBool(bool(*literal.Value)), nil
}