243 lines
7.5 KiB
Go
243 lines
7.5 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) {
|
|
base := analyzer.ReduceToBase(literal.Type())
|
|
|
|
makeData := func (elementType entity.Type, irArrayType llvm.Type) (llvm.Value, error) {
|
|
if irArrayType == nil {
|
|
var err 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 base := base.(type) {
|
|
case *entity.TypeArray:
|
|
irArrayType, err := this.generateType(literal.Type())
|
|
if err != nil { return nil, err }
|
|
return makeData(base.Element, irArrayType)
|
|
|
|
case *entity.TypeSlice:
|
|
array, err := makeData(base.Element, nil)
|
|
if err != nil { return nil, err }
|
|
return this.generateSliceDefinedLength(base, array, int64(len(literal.Elements)))
|
|
|
|
case *entity.TypePointer:
|
|
array, err := makeData(base.Referenced, nil)
|
|
if err != nil { return nil, err }
|
|
return this.valueToLocation(array), nil
|
|
|
|
default:
|
|
return nil, errors.New(fmt.Sprintln("array can't be used as ", base))
|
|
}
|
|
}
|
|
|
|
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.generateSliceDefinedLength(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) {
|
|
base, ok := analyzer.ReduceToBase(literal.Type()).(*entity.TypeStruct)
|
|
if !ok { return nil, errors.New(fmt.Sprintln("struct can't be used as ", literal.Type())) }
|
|
|
|
irType, err := this.generateType(literal.Type())
|
|
if err != nil { return nil, err }
|
|
|
|
structure := this.blockManager.newAllocaFront(irType)
|
|
|
|
for index, member := range base.Members {
|
|
var irMember llvm.Value
|
|
if pair, ok := literal.MemberMap[member.Name]; ok {
|
|
irMember, err = this.generateExpressionVal(pair.Value)
|
|
if err != nil { return nil, err }
|
|
} else {
|
|
irMemberType, err := this.generateType(member.Type())
|
|
if err != nil { return nil, err }
|
|
irMember = llvm.NewConstZeroInitializer(irMemberType)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (this *generator) generateLiteralNil (literal *entity.LiteralNil) (llvm.Value, error) {
|
|
ty, err := this.generateType(literal.Type())
|
|
if err != nil { return nil, err }
|
|
return llvm.NewConstZeroInitializer(ty), nil
|
|
}
|