That should be literally every feature
This commit is contained in:
parent
ea502dc2bb
commit
3f88513dc1
|
@ -1,5 +1,7 @@
|
|||
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"
|
||||
|
@ -27,24 +29,93 @@ func (this *generator) generateAssignmentSource (
|
|||
) {
|
||||
source, err := this.generateExpression(from)
|
||||
if err != nil { return nil, err }
|
||||
ty := analyzer.ReduceToBase(to)
|
||||
toBase := analyzer.ReduceToBase(to)
|
||||
|
||||
switch /*ty := */ty.(type) {
|
||||
switch toBase := toBase.(type) {
|
||||
// conversion from any type to interface
|
||||
case *entity.TypeInterface:
|
||||
// TODO: assign to interface
|
||||
// sourceTy := analyzer.ReduceToBase(from.Type())
|
||||
// irSourceTy, err := this,generateType(sourceTy)
|
||||
// if err != nil { return nil, err }
|
||||
//
|
||||
// if
|
||||
//
|
||||
// irType, err := this.generateType(to)
|
||||
// if err != nil { return nil, err }
|
||||
// pointer := this.
|
||||
// methods defined on interface or pointer types cannot pass
|
||||
// through an interface!
|
||||
|
||||
// create destination interface
|
||||
irToType, err := this.generateType(to)
|
||||
if err != nil { return nil, err }
|
||||
destination := this.blockManager.newAllocaFront(irToType)
|
||||
toDataField := this.getInterfaceData(destination, irToType)
|
||||
|
||||
fromType := from.Type()
|
||||
switch fromBase := analyzer.ReduceToBase(fromType).(type) {
|
||||
// conversion from interface to interface
|
||||
case *entity.TypeInterface:
|
||||
// re-assign data
|
||||
irFromType, err := this.generateType(fromType)
|
||||
if err != nil { return nil, err }
|
||||
fromDataField := this.getInterfaceData(source, irFromType)
|
||||
fromData := this.blockManager.NewLoad(new(llvm.TypePointer), fromDataField)
|
||||
this.blockManager.NewStore(fromData, toDataField)
|
||||
|
||||
// re-assign behaviors
|
||||
for _, name := range toBase.BehaviorOrder {
|
||||
fromBehaviorField := this.getInterfaceBehavior (
|
||||
fromBase, source,
|
||||
irFromType, name)
|
||||
toBehaviorField := this.getInterfaceBehavior (
|
||||
toBase, source,
|
||||
irToType, name)
|
||||
fromBehavior := this.blockManager.NewLoad(new(llvm.TypePointer), fromBehaviorField)
|
||||
this.blockManager.NewStore(fromBehavior, toBehaviorField)
|
||||
}
|
||||
|
||||
// conversion from pointer to interface
|
||||
case *entity.TypePointer:
|
||||
// assign data
|
||||
fromData := this.blockManager.NewLoad(new(llvm.TypePointer), source)
|
||||
this.blockManager.NewStore(fromData, toDataField)
|
||||
|
||||
fromReferenced, ok := fromBase.Referenced.(*entity.TypeNamed)
|
||||
if !ok {
|
||||
return nil, errors.New(fmt.Sprint(
|
||||
"can't assign", fromBase, "to interface"))
|
||||
}
|
||||
|
||||
// assign behaviors
|
||||
for _, name := range toBase.BehaviorOrder {
|
||||
toBehaviorField := this.getInterfaceBehavior (
|
||||
toBase, source,
|
||||
irToType, name)
|
||||
fromBehavior, err := this.method(fromReferenced.Name, name)
|
||||
if err != nil { return nil, err }
|
||||
this.blockManager.NewStore(fromBehavior, toBehaviorField)
|
||||
}
|
||||
|
||||
// conversion from other type to interface
|
||||
default:
|
||||
// assign data
|
||||
this.blockManager.NewStore(source, toDataField)
|
||||
|
||||
fromType, ok := fromType.(*entity.TypeNamed)
|
||||
if !ok {
|
||||
return nil, errors.New(fmt.Sprint(
|
||||
"can't assign", fromBase, "to interface"))
|
||||
}
|
||||
|
||||
// assign behaviors
|
||||
for _, name := range toBase.BehaviorOrder {
|
||||
toBehaviorField := this.getInterfaceBehavior (
|
||||
toBase, source,
|
||||
irToType, name)
|
||||
fromBehavior, err := this.method(fromType.Name, name)
|
||||
if err != nil { return nil, err }
|
||||
this.blockManager.NewStore(fromBehavior, toBehaviorField)
|
||||
}
|
||||
}
|
||||
|
||||
// conversion from array to slice
|
||||
case *entity.TypeSlice:
|
||||
/*if fromType, ok := analyzer.ReduceToBase(from.Type()).(*entity.TypeArray); ok {
|
||||
// TODO: convert array to slice
|
||||
}*/
|
||||
switch fromBase := analyzer.ReduceToBase(from.Type()).(type) {
|
||||
case *entity.TypeArray:
|
||||
return this.generateSlice(to, source, 0, int64(fromBase.Length))
|
||||
}
|
||||
}
|
||||
return source, nil
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ package generator
|
|||
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||
|
||||
func (this *generator) generateSlice (ty *entity.TypeSlice, data llvm.Value, start, end int64) (llvm.Value, error) {
|
||||
irType, err := this.generateTypeSlice(ty)
|
||||
func (this *generator) generateSlice (ty entity.Type, data llvm.Value, start, end int64) (llvm.Value, error) {
|
||||
irType, err := this.generateType(ty)
|
||||
if err != nil { return nil, err }
|
||||
|
||||
slice := this.blockManager.newAllocaFront(irType)
|
||||
|
@ -31,3 +31,42 @@ func (this *generator) generateSlice (ty *entity.TypeSlice, data llvm.Value, sta
|
|||
endField)
|
||||
return slice, nil
|
||||
}
|
||||
|
||||
func (this *generator) getInterfaceData (iface llvm.Value, irType llvm.Type) llvm.Value {
|
||||
return this.blockManager.NewGetElementPtr (
|
||||
irType, iface,
|
||||
llvm.NewConstInt(llvm.I32, 0),
|
||||
llvm.NewConstInt(llvm.I32, 0))
|
||||
}
|
||||
|
||||
func (this *generator) getInterfaceBehavior (
|
||||
ty *entity.TypeInterface,
|
||||
iface llvm.Value,
|
||||
irType llvm.Type,
|
||||
name string,
|
||||
) llvm.Value {
|
||||
offset := this.getInterfaceBehaviorIndex(ty, name)
|
||||
if offset > -1 {
|
||||
return this.blockManager.NewGetElementPtr (
|
||||
irType, iface,
|
||||
llvm.NewConstInt(llvm.I32, 0),
|
||||
llvm.NewConstInt(llvm.I32, int64(offset + 1)))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (this *generator) getInterfaceBehaviorSignature (ty *entity.TypeInterface, name string) (llvm.Type, error) {
|
||||
return this.generateTypeFunction(ty.BehaviorMap[name])
|
||||
}
|
||||
|
||||
func (this *generator) getInterfaceBehaviorIndex (ty *entity.TypeInterface, name string) int {
|
||||
offset := -1
|
||||
for index, nm := range ty.BehaviorOrder {
|
||||
if nm == name {
|
||||
offset = index
|
||||
break
|
||||
}
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
|
|
@ -70,29 +70,13 @@ func (this *generator) generateMethodCall (call *entity.MethodCall) (llvm.Value,
|
|||
|
||||
// check for interface behaviors
|
||||
if sourceType := getInterface(call.Source.Type()); sourceType != nil {
|
||||
// find offset of the behavior's function pointer
|
||||
offset := -1
|
||||
for index, name := range sourceType.BehaviorOrder {
|
||||
if name == call.Name {
|
||||
offset = index
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if offset > -1 {
|
||||
// get the value pointer
|
||||
irValue := this.blockManager.NewGetElementPtr (
|
||||
source.Type(), source,
|
||||
llvm.NewConstInt(llvm.I32, 0),
|
||||
llvm.NewConstInt(llvm.I32, 0))
|
||||
// get the behavior pointer
|
||||
irBehavior := this.blockManager.NewGetElementPtr (
|
||||
source.Type(), source,
|
||||
llvm.NewConstInt(llvm.I32, 0),
|
||||
llvm.NewConstInt(llvm.I32, int64(offset + 1)))
|
||||
// get the behavior's signature
|
||||
signature, err := this.generateTypeFunction (
|
||||
sourceType.BehaviorMap[call.Name])
|
||||
irSourceType, err := this.generateType(sourceType)
|
||||
if err != nil { return nil, err }
|
||||
irBehavior := this.getInterfaceBehavior(sourceType, source, irSourceType, call.Name)
|
||||
|
||||
if irBehavior != nil {
|
||||
irValue := this.getInterfaceData(source, irSourceType)
|
||||
signature, err := this.getInterfaceBehaviorSignature(sourceType, call.Name)
|
||||
if err != nil { return nil, err }
|
||||
|
||||
args[0] = this.blockManager.NewLoad(irValue.Type(), irValue)
|
||||
|
|
|
@ -38,3 +38,42 @@ func (this *generator) generateFunction (
|
|||
}
|
||||
return irFunc, nil
|
||||
}
|
||||
|
||||
func (this *generator) generateMethod (
|
||||
method *entity.Method,
|
||||
) (
|
||||
*llvm.Function,
|
||||
error,
|
||||
) {
|
||||
params := make([]*llvm.Parameter, len(method.Signature.Arguments) + 1)
|
||||
|
||||
ret, err := this.generateType(method.Signature.Return)
|
||||
if err != nil { return nil, err }
|
||||
|
||||
for index, argument := range method.Signature.Arguments {
|
||||
paramType, err := this.generateType(argument.Type())
|
||||
if err != nil { return nil, err }
|
||||
params[index + 1] = llvm.NewParameter(argument.Name, paramType)
|
||||
}
|
||||
ownerType, err := this.typedef(method.TypeName)
|
||||
if err != nil { return nil, err }
|
||||
params[0] = llvm.NewParameter("this", ownerType)
|
||||
|
||||
irFunc := this.module.NewFunction(method.Signature.Name, ret, params...)
|
||||
|
||||
if method.Body != nil {
|
||||
this.blockManager = this.pushBlockManager(irFunc)
|
||||
defer this.popBlockManager()
|
||||
|
||||
this.blockManager.addDeclarationsInFunction(method)
|
||||
body, err := this.generateExpression(method.Body)
|
||||
if err != nil { return nil, err }
|
||||
|
||||
if method.Signature.Return == nil {
|
||||
this.blockManager.NewRet(nil)
|
||||
} else {
|
||||
this.blockManager.NewRet(body)
|
||||
}
|
||||
}
|
||||
return irFunc, nil
|
||||
}
|
||||
|
|
|
@ -6,17 +6,28 @@ func TestFunction (test *testing.T) {
|
|||
testString (test,
|
||||
`
|
||||
`,
|
||||
`[puts string:*Byte]:I32
|
||||
`
|
||||
[puts string:*Byte]:I32
|
||||
[read fd:Int buf:*Byte count:Index]:Index
|
||||
|
||||
[itoa value:Int buffer:String base:Int]:String = {
|
||||
if [== base 0] then { base = 10 }
|
||||
index:Index = 0
|
||||
|
||||
loop {
|
||||
digit:Int = [% value base]
|
||||
[.buffer index] = [~Byte [+ digit '0']]
|
||||
value = [/ value base]
|
||||
index = [++index]
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
[main argc:I32 argv:**Byte] = {
|
||||
[puts 'allocing buffer']
|
||||
buffer:*:Byte = bufferData:8:Byte
|
||||
[puts 'reading into buffer']
|
||||
[read 1 [~ *Byte buffer] 7]
|
||||
[puts 'adding a null terminator at offset 7']
|
||||
[. buffer 7] = 0
|
||||
[puts 'echoing buffer']
|
||||
[puts [~ *Byte buffer]]
|
||||
[itoa 5 string:16:Byte 10]
|
||||
[.string 15] = 0
|
||||
[puts [.[@string]]]
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
|
|
@ -67,20 +67,18 @@ func (this *generator) method (typeName string, name string) (*llvm.Function, er
|
|||
return function, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
// TODO uncomment when generateMethod is added
|
||||
// ty, exists := this.tree.Types[typeName]
|
||||
// if !exists {
|
||||
// return nil,
|
||||
// errors.New(fmt.Sprintln("type", typeName, "not found"))
|
||||
// }
|
||||
// function, exists := ty.Methods[name]
|
||||
// if !exists {
|
||||
// return nil, errors.New(fmt.Sprintln (
|
||||
// "method", typeName + "." + name, "not found"))
|
||||
// }
|
||||
// // return this.generateMethod(function), nil
|
||||
|
||||
ty, exists := this.tree.Types[typeName]
|
||||
if !exists {
|
||||
return nil,
|
||||
errors.New(fmt.Sprintln("type", typeName, "not found"))
|
||||
}
|
||||
method, exists := ty.Methods[name]
|
||||
if !exists {
|
||||
return nil, errors.New(fmt.Sprintln (
|
||||
"method", typeName + "." + name, "not found"))
|
||||
}
|
||||
return this.generateMethod(method)
|
||||
}
|
||||
|
||||
func (this *generator) function (name string) (*llvm.Function, error) {
|
||||
|
|
Loading…
Reference in New Issue