fspl/generator/expression-loc.go

163 lines
5.0 KiB
Go

package generator
import "fmt"
import "git.tebibyte.media/fspl/fspl/llvm"
import "git.tebibyte.media/fspl/fspl/entity"
import "git.tebibyte.media/fspl/fspl/analyzer"
func (this *generator) generateVariableLoc (variable *entity.Variable) (llvm.Value, error) {
return this.blockManager.variable(variable.Declaration)
}
func (this *generator) generateDeclarationLoc (declaration *entity.Declaration) (llvm.Value, error) {
return this.blockManager.addDeclaration(declaration, nil)
}
func (this *generator) generateSliceLoc (slice *entity.Slice) (llvm.Value, error) {
var start, end, dataAddress llvm.Value
var elementType llvm.Type
sizeType, err := this.generateTypeIndex()
if err != nil { return nil, err }
if slice.Start != nil {
start, err = this.generateExpressionVal(slice.Start)
if err != nil { return nil, err }
}
if slice.End != nil {
end, err = this.generateExpressionVal(slice.End)
if err != nil { return nil, err }
}
sourceType := analyzer.ReduceToBase(slice.Slice.Type())
switch sourceType := sourceType.(type) {
case *entity.TypeSlice:
source, err := this.generateExpressionLoc(slice.Slice)
if err != nil { return nil, err }
irSourceType, err := this.generateType(sourceType)
if err != nil { return nil, err }
elementType, err = this.generateType(sourceType.Element)
if err != nil { return nil, err }
dataAddressFieldAddress := this.blockManager.NewGetElementPtr (
irSourceType,
source,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, 0))
dataAddress = this.blockManager.NewLoad (
new(llvm.TypePointer),
dataAddressFieldAddress)
lengthAddress := this.blockManager.NewGetElementPtr (
irSourceType,
source,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, 1))
if end == nil {
end = this.blockManager.NewLoad(sizeType, lengthAddress)
}
case *entity.TypeArray:
elementType, err = this.generateType(sourceType.Element)
if err != nil { return nil, err }
dataAddress, err = this.generateExpressionLoc(slice.Slice)
if err != nil { return nil, err }
if end == nil {
end = llvm.NewConstInt(sizeType, int64(sourceType.Length))
}
default:
panic(fmt.Sprint (
"BUG: generator can't slice expression ",
slice.Slice))
}
// figure out starting position and length
var length llvm.Value
if start == nil {
length = end
} else {
length = this.blockManager.NewSub(end, start)
dataAddress = this.blockManager.NewGetElementPtr (
elementType,
dataAddress,
start)
}
// create new slice descriptor
return this.generateSlice(slice.Type(), dataAddress, length)
}
func (this *generator) generateSubscriptLoc (subscript *entity.Subscript) (llvm.Value, error) {
source, err := this.generateExpressionLoc(subscript.Slice)
if err != nil { return nil, err }
offset, err := this.generateExpressionVal(subscript.Offset)
if err != nil { return nil, err }
var elementType entity.Type
var dataAddress llvm.Value
sourceType := analyzer.ReduceToBase(subscript.Slice.Type())
switch sourceType := sourceType.(type) {
case *entity.TypeSlice:
irSourceType, err := this.generateType(subscript.Slice.Type())
if err != nil { return nil, err }
elementType = sourceType.Element
dataAddress = this.getSliceDataAddress(source, irSourceType)
case *entity.TypeArray:
elementType = sourceType.Element
dataAddress = source
default:
panic(fmt.Sprint (
"BUG: generator can't subscript expression ",
subscript.Slice))
}
// get element
irElementType, err := this.generateType(elementType)
if err != nil { return nil, err }
return this.blockManager.NewGetElementPtr (
irElementType,
dataAddress,
offset), nil
}
func (this *generator) generateDereferenceLoc (dereference *entity.Dereference) (llvm.Value, error) {
return this.generateExpressionVal(dereference.Pointer)
}
func (this *generator) generateMemberAccessLoc (access *entity.MemberAccess) (llvm.Value, error) {
source, err := this.generateExpressionLoc(access.Source)
if err != nil { return nil, err }
switch sourceType := analyzer.ReduceToBase(access.Source.Type()).(type) {
case *entity.TypeStruct:
irSourceType, err := this.generateType(access.Source.Type())
if err != nil { return nil, err }
offset := this.getStructMemberIndex(sourceType, access.Member)
return this.blockManager.NewGetElementPtr (
irSourceType,
source,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, int64(offset))), nil
case *entity.TypePointer:
irSourceType, err := this.generateType(sourceType.Referenced)
if err != nil { return nil, err }
referencedSourceType := analyzer.ReduceToBase(sourceType.Referenced).(*entity.TypeStruct)
offset := this.getStructMemberIndex(referencedSourceType, access.Member)
source = this.blockManager.NewLoad(new(llvm.TypePointer), source)
return this.blockManager.NewGetElementPtr (
irSourceType,
source,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, int64(offset))), nil
default:
panic(fmt.Sprint (
"BUG: generator can't access members in expression ",
access.Source))
}
}