163 lines
5.0 KiB
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))
|
|
}
|
|
}
|