Merge pull request 'generator-multi-unit-tests' (#51) from generator-multi-unit-tests into main
Reviewed-on: #51
This commit is contained in:
commit
8e3b21f807
|
@ -124,7 +124,7 @@ func (this *generator) generateAssignmentToDestination ( // TODO: add -Val suffi
|
|||
destTypeBase, irDestLoc,
|
||||
irDestType, name)
|
||||
key := entity.Key {
|
||||
Unit: sourceType.Unit(),
|
||||
Unit: sourceType.Type.Unit(),
|
||||
Name: sourceType.Name,
|
||||
Method: name,
|
||||
}
|
||||
|
|
|
@ -86,3 +86,44 @@ define void @"0zNZN147MN2wzMAQ6NS2dQ==::main"() {
|
|||
}
|
||||
`)
|
||||
}
|
||||
|
||||
// TODO: Perhaps run all generator output in these tests through llc to check the
|
||||
// integrity of the IR.
|
||||
|
||||
// TODO: uncomment and complete once bitcasting is fully supported
|
||||
// func TestBitCastPointer (test *testing.T) {
|
||||
// testString (test,
|
||||
// `
|
||||
// `,
|
||||
// `
|
||||
// Struct: (. x:Int y:Int)
|
||||
// Array: 4:Int
|
||||
// [main] = {
|
||||
// ptr:*Byte
|
||||
// stc:Struct
|
||||
// arr:Array
|
||||
// str:String
|
||||
// flt:F64
|
||||
// idx:Index
|
||||
//
|
||||
// ; struct
|
||||
// ptr = [~~*Byte [~~Struct ptr]]
|
||||
// stc = [~~Struct [~~*Byte stc]]
|
||||
// ; array
|
||||
// ptr = [~~*Byte [~~Array ptr]]
|
||||
// arr = [~~Array [~~*Byte arr]]
|
||||
// ; slice
|
||||
// ptr = [~~*Byte [~~String ptr]]
|
||||
// str = [~~String [~~*Byte str]]
|
||||
// ; int
|
||||
// ptr = [~~*Byte [~~Index ptr]]
|
||||
// idx = [~~Index [~~*Byte idx]]
|
||||
// ; float
|
||||
// ptr = [~~*Byte [~~F64 ptr]]
|
||||
// flt = [~~F64 [~~*Byte flt]]
|
||||
//
|
||||
// ; arithmetic
|
||||
// ptr = [~~*Byte [+ 1 [~~Index ptr]]]
|
||||
// }
|
||||
// `)
|
||||
// }
|
||||
|
|
|
@ -44,11 +44,12 @@ func (this *generator) generateMethodCallVal (call *entity.MethodCall) (llvm.Val
|
|||
|
||||
// check for methods on named type
|
||||
if sourceType, ok := call.Source.Type().(*entity.TypeNamed); ok {
|
||||
method, err := this.method(entity.Key {
|
||||
Unit: sourceType.Unit(),
|
||||
methodKey := entity.Key {
|
||||
Unit: sourceType.Type.Unit(),
|
||||
Name: sourceType.Name,
|
||||
Method: call.Name,
|
||||
})
|
||||
}
|
||||
method, err := this.method(methodKey)
|
||||
if _, notFound := err.(errNotFound); !notFound {
|
||||
source, err := this.generateExpressionLoc(call.Source)
|
||||
if err != nil { return nil, err }
|
||||
|
@ -263,18 +264,52 @@ func (this *generator) generateBitCastVal (cast *entity.BitCast) (llvm.Value, er
|
|||
irToType, err := this.generateType(cast.Type())
|
||||
if err != nil { return nil, err }
|
||||
|
||||
// Attempt to short circuit if types are equal to avoid LLVM bitching at
|
||||
// us
|
||||
// attempt to short circuit if types are equal, or else LLVM complains
|
||||
if llvm.TypesEqual(irFromType, irToType) {
|
||||
return this.generateExpressionVal(cast.Value)
|
||||
}
|
||||
|
||||
from, err := this.generateExpressionVal(cast.Value)
|
||||
if err != nil { return nil, err }
|
||||
|
||||
// determine how to *bit cast*. because of course its not that simple.
|
||||
// thanks LLVM!
|
||||
fromType := analyzer.ReduceToBase(cast.Value.Type())
|
||||
toType := analyzer.ReduceToBase(cast.Type())
|
||||
switch toType.(type) {
|
||||
case *entity.TypeInt, *entity.TypeWord:
|
||||
switch fromType.(type) {
|
||||
case *entity.TypePointer:
|
||||
// cast from pointer to int
|
||||
return this.blockManager.NewPtrToInt(from, irToType), nil
|
||||
}
|
||||
case *entity.TypePointer:
|
||||
switch fromType.(type) {
|
||||
case *entity.TypeInt, *entity.TypeWord:
|
||||
// cast from int to pointer
|
||||
return this.blockManager.NewIntToPtr(from, irToType), nil
|
||||
default:
|
||||
// cast from something else to pointer
|
||||
irIndexType, err := this.generateTypeIndex()
|
||||
if err != nil { return nil, err }
|
||||
temporaryInteger := this.blockManager.NewBitCast(from, irIndexType)
|
||||
return this.blockManager.NewIntToPtr(temporaryInteger, irToType), nil
|
||||
}
|
||||
default:
|
||||
switch fromType.(type) {
|
||||
case *entity.TypePointer:
|
||||
// cast from pointer to something else
|
||||
irIndexType, err := this.generateTypeIndex()
|
||||
if err != nil { return nil, err }
|
||||
temporaryInteger := this.blockManager.NewPtrToInt(from, irIndexType)
|
||||
return this.blockManager.NewBitCast(temporaryInteger, irToType), nil
|
||||
}
|
||||
}
|
||||
|
||||
// default to a normal bit cast
|
||||
return this.blockManager.NewBitCast(from, irToType), nil
|
||||
}
|
||||
|
||||
|
||||
func (this *generator) generateOperationVal (operation *entity.Operation) (llvm.Value, error) {
|
||||
nSameType := func (binary func (x, y llvm.Value) llvm.Value) (llvm.Value, error) {
|
||||
irX, err := this.generateExpressionVal(operation.Arguments[0])
|
||||
|
|
|
@ -86,7 +86,7 @@ func (this *generator) method (key entity.Key) (*llvm.Function, error) {
|
|||
|
||||
ty, exists := this.tree.Types[key.StripMethod()]
|
||||
if !exists {
|
||||
return nil, errNotFound("method " + key.String())
|
||||
return nil, errNotFound("owner of method " + key.String())
|
||||
}
|
||||
|
||||
if method, exists := ty.Methods[key.Method]; exists {
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
package generator
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestUnitTwo (test *testing.T) {
|
||||
testUnits (test,
|
||||
`%"E80Pxr3rNdulEDOmHs9Hsg==::X" = type i64
|
||||
define %"E80Pxr3rNdulEDOmHs9Hsg==::X" @"0zNZN147MN2wzMAQ6NS2dQ==::main"() {
|
||||
0:
|
||||
ret i64 5
|
||||
}
|
||||
`,
|
||||
`[main]:something::X = 5`,
|
||||
|
||||
"something.fspl",
|
||||
`+ X:Int`,
|
||||
)}
|
||||
|
||||
func TestUnitAssignRestricted (test *testing.T) {
|
||||
testUnits (test,
|
||||
`%"s0sfKEEPN2W0H9cNKD+OOg==::RestrictedInt" = type i64
|
||||
define void @"0zNZN147MN2wzMAQ6NS2dQ==::main"() {
|
||||
0:
|
||||
%1 = alloca %"s0sfKEEPN2W0H9cNKD+OOg==::RestrictedInt"
|
||||
%2 = alloca %"s0sfKEEPN2W0H9cNKD+OOg==::RestrictedInt"
|
||||
%3 = load %"s0sfKEEPN2W0H9cNKD+OOg==::RestrictedInt", ptr %2
|
||||
store %"s0sfKEEPN2W0H9cNKD+OOg==::RestrictedInt" %3, ptr %1
|
||||
ret void
|
||||
}
|
||||
`,
|
||||
`[main] = {
|
||||
x:other::RestrictedInt
|
||||
y:other::RestrictedInt
|
||||
x = y
|
||||
}`,
|
||||
|
||||
"other.fspl",
|
||||
`~ RestrictedInt:Int`,
|
||||
)}
|
||||
|
||||
func TestNestedUnitTypedef (test *testing.T) {
|
||||
testUnits (test,
|
||||
`%"kOsrvvRIOh2nYGTmlfGyKQ==::X" = type i64
|
||||
%"qnTuCId6O/ihTdVz5Ln6WQ==::X" = type %"kOsrvvRIOh2nYGTmlfGyKQ==::X"
|
||||
define %"qnTuCId6O/ihTdVz5Ln6WQ==::X" @"0zNZN147MN2wzMAQ6NS2dQ==::main"() {
|
||||
0:
|
||||
ret i64 5
|
||||
}
|
||||
`,
|
||||
`[main]:layer1::X = 5`,
|
||||
|
||||
"layer0.fspl",
|
||||
`+ X:Int`,
|
||||
|
||||
"layer1.fspl",
|
||||
`+ X:layer0::X`,
|
||||
)}
|
||||
|
||||
func TestUnitInterfaceSatisfaction (test *testing.T) {
|
||||
testUnits (test,
|
||||
`%"AAAAAAAAAAAAAAAAAAAAAA==::Index" = type i64
|
||||
%"qsUY87+PPGG/YPYMcnGU/g==::FileDescriptor" = type i64
|
||||
%"1cqXRNyHN06gi9QQb4GCsg==::File" = type %"qsUY87+PPGG/YPYMcnGU/g==::FileDescriptor"
|
||||
%"1cqXRNyHN06gi9QQb4GCsg==::Writer" = type { ptr, ptr }
|
||||
%"AAAAAAAAAAAAAAAAAAAAAA==::Byte" = type i8
|
||||
declare %"AAAAAAAAAAAAAAAAAAAAAA==::Index" @write(%"qsUY87+PPGG/YPYMcnGU/g==::FileDescriptor" %file, ptr %buffer, %"AAAAAAAAAAAAAAAAAAAAAA==::Index" %count)
|
||||
define i32 @main() {
|
||||
0:
|
||||
%1 = alloca %"1cqXRNyHN06gi9QQb4GCsg==::File"
|
||||
store i64 1, ptr %1
|
||||
%2 = alloca %"1cqXRNyHN06gi9QQb4GCsg==::Writer"
|
||||
%3 = getelementptr %"1cqXRNyHN06gi9QQb4GCsg==::Writer", ptr %2, i32 0, i32 0
|
||||
store ptr %1, ptr %3
|
||||
%4 = getelementptr %"1cqXRNyHN06gi9QQb4GCsg==::Writer", ptr %2, i32 0, i32 1
|
||||
store ptr @"1cqXRNyHN06gi9QQb4GCsg==::File.write", ptr %4
|
||||
%5 = load %"1cqXRNyHN06gi9QQb4GCsg==::Writer", ptr %2
|
||||
call void @"0zNZN147MN2wzMAQ6NS2dQ==::sayHello"(%"1cqXRNyHN06gi9QQb4GCsg==::Writer" %5)
|
||||
ret i32 0
|
||||
}
|
||||
define void @"0zNZN147MN2wzMAQ6NS2dQ==::sayHello"(%"1cqXRNyHN06gi9QQb4GCsg==::Writer" %writer) {
|
||||
0:
|
||||
%1 = alloca %"1cqXRNyHN06gi9QQb4GCsg==::Writer"
|
||||
store %"1cqXRNyHN06gi9QQb4GCsg==::Writer" %writer, ptr %1
|
||||
%2 = alloca { ptr, %"AAAAAAAAAAAAAAAAAAAAAA==::Index" }
|
||||
%3 = alloca [3 x %"AAAAAAAAAAAAAAAAAAAAAA==::Byte"]
|
||||
%4 = getelementptr [3 x %"AAAAAAAAAAAAAAAAAAAAAA==::Byte"], ptr %3, i32 0, i32 0
|
||||
store i8 104, ptr %4
|
||||
%5 = getelementptr [3 x %"AAAAAAAAAAAAAAAAAAAAAA==::Byte"], ptr %3, i32 0, i32 1
|
||||
store i8 105, ptr %5
|
||||
%6 = getelementptr [3 x %"AAAAAAAAAAAAAAAAAAAAAA==::Byte"], ptr %3, i32 0, i32 2
|
||||
store i8 10, ptr %6
|
||||
%7 = getelementptr { ptr, %"AAAAAAAAAAAAAAAAAAAAAA==::Index" }, ptr %2, i32 0, i32 0
|
||||
store ptr %3, ptr %7
|
||||
%8 = getelementptr { ptr, %"AAAAAAAAAAAAAAAAAAAAAA==::Index" }, ptr %2, i32 0, i32 1
|
||||
store %"AAAAAAAAAAAAAAAAAAAAAA==::Index" 3, ptr %8
|
||||
%9 = load { ptr, %"AAAAAAAAAAAAAAAAAAAAAA==::Index" }, ptr %2
|
||||
%10 = getelementptr %"1cqXRNyHN06gi9QQb4GCsg==::Writer", ptr %1, i32 0, i32 1
|
||||
%11 = getelementptr %"1cqXRNyHN06gi9QQb4GCsg==::Writer", ptr %1, i32 0, i32 0
|
||||
%12 = load ptr, ptr %11
|
||||
%13 = load ptr, ptr %10
|
||||
%14 = call %"AAAAAAAAAAAAAAAAAAAAAA==::Index" %13(ptr %12, { ptr, %"AAAAAAAAAAAAAAAAAAAAAA==::Index" } %9)
|
||||
ret void
|
||||
}
|
||||
declare %"AAAAAAAAAAAAAAAAAAAAAA==::Index" @"1cqXRNyHN06gi9QQb4GCsg==::File.write"(ptr %this, { ptr, %"AAAAAAAAAAAAAAAAAAAAAA==::Index" } %buffer)
|
||||
`,
|
||||
`[sayHello writer:io::Writer] = writer.[write 'hi\n']
|
||||
|
||||
[main]: I32 'main' = {
|
||||
stdout:io::File = 1
|
||||
[sayHello stdout]
|
||||
0
|
||||
}`,
|
||||
|
||||
"cstdio.fspl",
|
||||
`+ FileDescriptor: Int
|
||||
+ [write file:FileDescriptor buffer:*Byte count:Index]: Index 'write'`,
|
||||
|
||||
"io.fspl",
|
||||
`+ Writer: (~ [write buffer:*:Byte]: Index)
|
||||
+ File: cstdio::FileDescriptor
|
||||
+ File.[write buffer:*:Byte]:Index =
|
||||
cstdio::[write
|
||||
[~cstdio::FileDescriptor [.this]]
|
||||
[~*Byte buffer] [#buffer]]`,
|
||||
)}
|
|
@ -18,7 +18,7 @@ func testString (test *testing.T, correct string, input string) {
|
|||
tree := analyzer.Tree { }
|
||||
err := tree.Analyze(address.UUID(), nil, ast)
|
||||
if err != nil {
|
||||
test.Error("analyzer returned error:", err)
|
||||
test.Error("analyzer returned error:\n" + errors.Format(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ func testUnits (
|
|||
// dependencies
|
||||
for index := 0; index < len(dependencies) - 1; index += 2 {
|
||||
address := entity.Address(dependencies[index])
|
||||
test.Log("analyzing", address, "UUID", address.UUID())
|
||||
source := dependencies[index + 1]
|
||||
ast, ok := treeOf(test, address, source, true)
|
||||
if !ok { return }
|
||||
|
@ -61,6 +62,7 @@ func testUnits (
|
|||
|
||||
// main
|
||||
address := entity.Address("main.fspl")
|
||||
test.Log("analyzing MAIN", address, "UUID", address.UUID())
|
||||
ast, ok := treeOf(test, address, main, false)
|
||||
if !ok { return }
|
||||
err := tree.Analyze(address.UUID(), nicknames, ast)
|
||||
|
|
Loading…
Reference in New Issue