Generator now has module support
This commit is contained in:
parent
2f2e762d02
commit
306b029951
|
@ -84,7 +84,7 @@ func (this *generator) generateAssignmentToDestination ( // TODO: add -Val suffi
|
|||
sourceDataLoc := this.blockManager.NewLoad(new(llvm.TypePointer), source)
|
||||
this.blockManager.NewStore(sourceDataLoc, destDataFieldLoc)
|
||||
|
||||
fromReferenced, ok := sourceTypeBase.Referenced.(*entity.TypeNamed)
|
||||
sourceType, ok := sourceTypeBase.Referenced.(*entity.TypeNamed)
|
||||
if !ok {
|
||||
return nil, errors.New(fmt.Sprint(
|
||||
"can't assign", sourceTypeBase, "to interface"))
|
||||
|
@ -95,7 +95,12 @@ func (this *generator) generateAssignmentToDestination ( // TODO: add -Val suffi
|
|||
toBehaviorFieldAddress := this.getInterfaceBehaviorFieldLoc (
|
||||
destTypeBase, irDestLoc,
|
||||
irDestType, name)
|
||||
fromBehavior, err := this.method(fromReferenced.Name, name)
|
||||
key := entity.Key {
|
||||
Unit: sourceType.Unit(),
|
||||
Name: sourceType.Name,
|
||||
Method: name,
|
||||
}
|
||||
fromBehavior, err := this.method(key)
|
||||
if err != nil { return nil, err }
|
||||
this.blockManager.NewStore(fromBehavior, toBehaviorFieldAddress)
|
||||
}
|
||||
|
@ -118,7 +123,12 @@ func (this *generator) generateAssignmentToDestination ( // TODO: add -Val suffi
|
|||
toBehaviorFieldAddress := this.getInterfaceBehaviorFieldLoc (
|
||||
destTypeBase, irDestLoc,
|
||||
irDestType, name)
|
||||
fromBehavior, err := this.method(sourceType.Name, name)
|
||||
key := entity.Key {
|
||||
Unit: sourceType.Unit(),
|
||||
Name: sourceType.Name,
|
||||
Method: name,
|
||||
}
|
||||
fromBehavior, err := this.method(key)
|
||||
if err != nil { return nil, err }
|
||||
this.blockManager.NewStore(fromBehavior, toBehaviorFieldAddress)
|
||||
}
|
||||
|
|
|
@ -14,14 +14,11 @@ func (this *generator) generateDeclarationLoc (declaration *entity.Declaration)
|
|||
}
|
||||
|
||||
func (this *generator) generateSliceLoc (slice *entity.Slice) (llvm.Value, error) {
|
||||
var err error
|
||||
var start, end, dataAddress llvm.Value
|
||||
var elementType llvm.Type
|
||||
var sizeType *llvm.TypeInt; {
|
||||
ty, err := this.typedef("Index")
|
||||
if err != nil { return nil, err }
|
||||
sizeType = ty.(*llvm.TypeInt)
|
||||
}
|
||||
|
||||
sizeType, err := this.generateTypeIndex()
|
||||
if err != nil { return nil, err }
|
||||
|
||||
if slice.Start != nil {
|
||||
start, err = this.generateExpressionVal(slice.Start)
|
||||
|
|
|
@ -7,7 +7,10 @@ import "git.tebibyte.media/sashakoshka/fspl/entity"
|
|||
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
|
||||
|
||||
func (this *generator) generateCallVal (call *entity.Call) (llvm.Value, error) {
|
||||
function, err := this.function(call.Name)
|
||||
function, err := this.function(entity.Key {
|
||||
Unit: call.Unit,
|
||||
Name: call.Name,
|
||||
})
|
||||
if err != nil { return nil, err }
|
||||
|
||||
args := make([]llvm.Value, len(call.Arguments))
|
||||
|
@ -41,7 +44,11 @@ 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(sourceType.Name, call.Name)
|
||||
method, err := this.method(entity.Key {
|
||||
Unit: sourceType.Unit(),
|
||||
Name: sourceType.Name,
|
||||
Method: call.Name,
|
||||
})
|
||||
if err != errNotFound {
|
||||
source, err := this.generateExpressionLoc(call.Source)
|
||||
if err != nil { return nil, err }
|
||||
|
@ -53,7 +60,11 @@ func (this *generator) generateMethodCallVal (call *entity.MethodCall) (llvm.Val
|
|||
// check for methods on pointer to named type
|
||||
if pointerType, ok := call.Source.Type().(*entity.TypePointer); ok {
|
||||
if sourceType, ok := pointerType.Referenced.(*entity.TypeNamed); ok {
|
||||
method, err := this.method(sourceType.Name, call.Name)
|
||||
method, err := this.method(entity.Key {
|
||||
Unit: sourceType.Unit(),
|
||||
Name: sourceType.Name,
|
||||
Method: call.Name,
|
||||
})
|
||||
if err != errNotFound {
|
||||
source, err := this.generateExpressionVal(call.Source)
|
||||
if err != nil { return nil, err }
|
||||
|
@ -93,11 +104,8 @@ func (this *generator) generateReferenceVal (reference *entity.Reference) (llvm.
|
|||
}
|
||||
|
||||
func (this *generator) generateLengthVal (length *entity.Length) (llvm.Value, error) {
|
||||
var sizeType *llvm.TypeInt; {
|
||||
ty, err := this.typedef("Index")
|
||||
if err != nil { return nil, err }
|
||||
sizeType = ty.(*llvm.TypeInt)
|
||||
}
|
||||
sizeType, err := this.generateTypeIndex()
|
||||
if err != nil { return nil, err }
|
||||
|
||||
source, err := this.generateExpressionLoc(length.Slice)
|
||||
if err != nil { return nil, err }
|
||||
|
|
|
@ -9,6 +9,11 @@ func (this *generator) generateFunction (
|
|||
*llvm.Function,
|
||||
error,
|
||||
) {
|
||||
key := entity.Key {
|
||||
Unit: function.Unit,
|
||||
Name: function.Signature.Name,
|
||||
}
|
||||
|
||||
params := make([]*llvm.Parameter, len(function.Signature.Arguments))
|
||||
|
||||
ret, err := this.generateType(function.Signature.Return)
|
||||
|
@ -21,7 +26,7 @@ func (this *generator) generateFunction (
|
|||
}
|
||||
|
||||
var name string; if function.LinkName == "" {
|
||||
name = function.Signature.Name
|
||||
name = key.LinkName()
|
||||
} else {
|
||||
name = function.LinkName
|
||||
}
|
||||
|
@ -44,7 +49,7 @@ func (this *generator) generateFunction (
|
|||
}
|
||||
}
|
||||
|
||||
this.functions[function.Signature.Name] = irFunc
|
||||
this.functions[key] = irFunc
|
||||
return irFunc, nil
|
||||
}
|
||||
|
||||
|
@ -54,6 +59,12 @@ func (this *generator) generateMethod (
|
|||
*llvm.Function,
|
||||
error,
|
||||
) {
|
||||
key := entity.Key {
|
||||
Unit: method.Unit,
|
||||
Name: method.TypeName,
|
||||
Method: method.Signature.Name,
|
||||
}
|
||||
|
||||
params := make([]*llvm.Parameter, len(method.Signature.Arguments) + 1)
|
||||
|
||||
ret, err := this.generateType(method.Signature.Return)
|
||||
|
@ -67,7 +78,7 @@ func (this *generator) generateMethod (
|
|||
params[0] = llvm.NewParameter("this", new(llvm.TypePointer))
|
||||
|
||||
var name string; if method.LinkName == "" {
|
||||
name = method.TypeName + "." + method.Signature.Name
|
||||
name = key.LinkName()
|
||||
} else {
|
||||
name = method.LinkName
|
||||
}
|
||||
|
@ -90,6 +101,6 @@ func (this *generator) generateMethod (
|
|||
}
|
||||
}
|
||||
|
||||
this.functions[method.TypeName + "." + method.Signature.Name] = irFunc
|
||||
this.functions[key] = irFunc
|
||||
return irFunc, nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package generator
|
|||
import "sort"
|
||||
import "errors"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
|
||||
|
||||
var errNotFound = errors.New("entity not found")
|
||||
|
@ -22,7 +23,8 @@ type generator struct {
|
|||
tree analyzer.Tree
|
||||
module *llvm.Module
|
||||
|
||||
functions map[string] *llvm.Function
|
||||
types map[entity.Key] llvm.Type
|
||||
functions map[entity.Key] *llvm.Function
|
||||
|
||||
managerStack []*blockManager
|
||||
blockManager *blockManager
|
||||
|
@ -36,25 +38,28 @@ func (this Target) Generate (tree analyzer.Tree) (*llvm.Module, error) {
|
|||
module: new(llvm.Module),
|
||||
target: this,
|
||||
tree: tree,
|
||||
functions: make(map[string] *llvm.Function),
|
||||
types: make(map[entity.Key] llvm.Type),
|
||||
functions: make(map[entity.Key] *llvm.Function),
|
||||
}).generate()
|
||||
}
|
||||
|
||||
func (this *generator) generate () (*llvm.Module, error) {
|
||||
// generate functions
|
||||
functions := sortMapKeys(this.tree.Functions)
|
||||
for _, functionName := range functions {
|
||||
_, err := this.function(functionName)
|
||||
functions := sortKeyedMapKeys(this.tree.Functions)
|
||||
for _, key := range functions {
|
||||
_, err := this.function(key)
|
||||
if err != nil { return nil, err }
|
||||
}
|
||||
|
||||
// generate methods
|
||||
types := sortMapKeys(this.tree.Types)
|
||||
for _, typeName := range types {
|
||||
ty := this.tree.Types[typeName]
|
||||
types := sortKeyedMapKeys(this.tree.Types)
|
||||
for _, key := range types {
|
||||
ty := this.tree.Types[key]
|
||||
methods := sortMapKeys(ty.Methods)
|
||||
for _, methodName := range methods {
|
||||
_, err := this.method(typeName, methodName)
|
||||
methodKey := key
|
||||
methodKey.Method = methodName
|
||||
_, err := this.method(methodKey)
|
||||
if err != nil { return nil, err }
|
||||
}
|
||||
}
|
||||
|
@ -62,39 +67,37 @@ func (this *generator) generate () (*llvm.Module, error) {
|
|||
return this.module, nil
|
||||
}
|
||||
|
||||
func (this *generator) typedef (typeName string) (llvm.Type, error) {
|
||||
for _, ty := range this.module.Types {
|
||||
if ty.Name() == typeName {
|
||||
return ty, nil
|
||||
}
|
||||
}
|
||||
def, exists := this.tree.Types[typeName]
|
||||
func (this *generator) typedef (key entity.Key) (llvm.Type, error) {
|
||||
ty, exists := this.types[key]
|
||||
if exists { return ty, nil }
|
||||
|
||||
def, exists := this.tree.Types[key]
|
||||
if !exists {
|
||||
return nil, errNotFound
|
||||
}
|
||||
return this.generateTypedef(def)
|
||||
}
|
||||
|
||||
func (this *generator) method (typeName string, name string) (*llvm.Function, error) {
|
||||
method, exists := this.functions[typeName + "." + name]
|
||||
func (this *generator) method (key entity.Key) (*llvm.Function, error) {
|
||||
method, exists := this.functions[key]
|
||||
if exists { return method, nil }
|
||||
|
||||
ty, exists := this.tree.Types[typeName]
|
||||
ty, exists := this.tree.Types[key.StripMethod()]
|
||||
if !exists {
|
||||
return nil, errNotFound
|
||||
}
|
||||
|
||||
if method, exists := ty.Methods[name]; exists {
|
||||
if method, exists := ty.Methods[key.Method]; exists {
|
||||
return this.generateMethod(method)
|
||||
}
|
||||
return nil, errNotFound
|
||||
}
|
||||
|
||||
func (this *generator) function (name string) (*llvm.Function, error) {
|
||||
function, exists := this.functions[name]
|
||||
func (this *generator) function (key entity.Key) (*llvm.Function, error) {
|
||||
function, exists := this.functions[key]
|
||||
if exists { return function, nil }
|
||||
|
||||
if function, exists := this.tree.Functions[name]; exists {
|
||||
if function, exists := this.tree.Functions[key]; exists {
|
||||
return this.generateFunction(function)
|
||||
}
|
||||
return nil, errNotFound
|
||||
|
@ -110,3 +113,36 @@ func sortMapKeys[T any] (unsorted map[string] T) []string {
|
|||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
type keySlice []entity.Key
|
||||
|
||||
func (keys keySlice) Len () int {
|
||||
return len(keys)
|
||||
}
|
||||
|
||||
func (keys keySlice) Less (lefti, righti int) bool {
|
||||
left := keys[lefti]
|
||||
right := keys[righti]
|
||||
|
||||
for index, leftByte := range left.Unit {
|
||||
if right.Unit[index] <= leftByte {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return left.Name < right.Name && left.Method < right.Method
|
||||
}
|
||||
|
||||
func (keys keySlice) Swap (lefti, righti int) {
|
||||
keys[lefti], keys[righti] = keys[righti], keys[lefti]
|
||||
}
|
||||
|
||||
func sortKeyedMapKeys[T any] (unsorted map[entity.Key] T) keySlice {
|
||||
keys := make(keySlice, len(unsorted))
|
||||
index := 0
|
||||
for key := range unsorted {
|
||||
keys[index] = key
|
||||
index ++
|
||||
}
|
||||
sort.Sort(keys)
|
||||
return keys
|
||||
}
|
||||
|
|
|
@ -1,33 +1,78 @@
|
|||
package generator
|
||||
|
||||
import "io"
|
||||
import "testing"
|
||||
import "strings"
|
||||
import "github.com/google/uuid"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/lexer"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/testcommon"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/parser/fspl"
|
||||
|
||||
func testString (test *testing.T, correct string, input string) {
|
||||
ast := fsplParser.Tree { }
|
||||
lx, err := lexer.LexReader("input.fspl", strings.NewReader(input))
|
||||
if err != nil {
|
||||
test.Error("lexer returned error:", err)
|
||||
return
|
||||
}
|
||||
err = ast.Parse(fsplParser.UnitInfo { }, lx)
|
||||
if err != nil && err != io.EOF{
|
||||
test.Error("parser returned error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
address := entity.Address("main.fspl")
|
||||
ast, ok := treeOf(test, address, input, false)
|
||||
if !ok { return }
|
||||
|
||||
tree := analyzer.Tree { }
|
||||
err = tree.Analyze(ast)
|
||||
err := tree.Analyze(address.UUID(), nil, ast)
|
||||
if err != nil {
|
||||
test.Error("analyzer returned error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
testSemanticTree(test, correct, input, tree)
|
||||
}
|
||||
|
||||
func testUnits (
|
||||
test *testing.T,
|
||||
correct string,
|
||||
main string,
|
||||
dependencies ...string,
|
||||
) {
|
||||
if len(dependencies) % 2 != 0 {
|
||||
panic("dependencies len must be even. forget an address?")
|
||||
}
|
||||
tree := analyzer.Tree { }
|
||||
nicknames := make(map[string] uuid.UUID)
|
||||
|
||||
// dependencies
|
||||
for index := 0; index < len(dependencies) - 1; index += 2 {
|
||||
address := entity.Address(dependencies[index])
|
||||
source := dependencies[index + 1]
|
||||
ast, ok := treeOf(test, address, source, true)
|
||||
if !ok { return }
|
||||
|
||||
err := tree.Analyze(address.UUID(), nicknames, ast)
|
||||
if err != nil {
|
||||
test.Error("analyzer returned error:\n" + errors.Format(err))
|
||||
return
|
||||
}
|
||||
|
||||
unit := address.UUID()
|
||||
nickname, ok := address.Nickname()
|
||||
if !ok {
|
||||
test.Errorf("could not generate nickname for %v", address)
|
||||
return
|
||||
}
|
||||
nicknames[nickname] = unit
|
||||
}
|
||||
|
||||
// main
|
||||
address := entity.Address("main.fspl")
|
||||
ast, ok := treeOf(test, address, main, false)
|
||||
if !ok { return }
|
||||
err := tree.Analyze(address.UUID(), nicknames, ast)
|
||||
if err != nil {
|
||||
test.Error("analyzer returned error:\n" + errors.Format(err))
|
||||
return
|
||||
}
|
||||
|
||||
testSemanticTree(test, correct, "", tree)
|
||||
}
|
||||
|
||||
func testSemanticTree (test *testing.T, correct string, input string, tree analyzer.Tree) {
|
||||
module, err := (&Target {
|
||||
WordSize: 64,
|
||||
Arch: "x86_64",
|
||||
|
@ -47,8 +92,32 @@ func testString (test *testing.T, correct string, input string) {
|
|||
if got != correct {
|
||||
test.Logf("results do not match")
|
||||
testcommon.Compare(test, correct, got)
|
||||
test.Log("SOURCE FSPL CODE:")
|
||||
test.Log("\033[32m" + input + "\033[0m")
|
||||
if input != "" {
|
||||
test.Log("SOURCE FSPL CODE:")
|
||||
test.Log("\033[32m" + input + "\033[0m")
|
||||
}
|
||||
test.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func treeOf (test *testing.T, address entity.Address, input string, skim bool) (fsplParser.Tree, bool) {
|
||||
ast := fsplParser.Tree { }
|
||||
lx, err := lexer.LexReader (
|
||||
string(address),
|
||||
strings.NewReader(input))
|
||||
if err != nil {
|
||||
test.Error("lexer returned error:\n" + errors.Format(err))
|
||||
return ast, false
|
||||
}
|
||||
if skim {
|
||||
err = ast.Skim(lx)
|
||||
} else {
|
||||
err = ast.Parse(lx)
|
||||
}
|
||||
if err != nil {
|
||||
test.Error("parser returned error:\n" + errors.Format(err))
|
||||
return ast, false
|
||||
}
|
||||
|
||||
return ast, true
|
||||
}
|
||||
|
|
|
@ -12,7 +12,12 @@ func (this *generator) generateTypedef (
|
|||
) {
|
||||
irType, err := this.generateType(def.Type)
|
||||
if err != nil { return nil, err }
|
||||
return this.module.NewType(def.Name, irType), nil
|
||||
irTypeDef := this.module.NewType(def.Name, irType)
|
||||
this.types[entity.Key {
|
||||
Unit: def.Unit,
|
||||
Name: def.Name,
|
||||
}] = irTypeDef
|
||||
return irTypeDef, nil
|
||||
}
|
||||
|
||||
func (this *generator) generateType (ty entity.Type) (llvm.Type, error) {
|
||||
|
@ -41,9 +46,3 @@ func (this *generator) generateType (ty entity.Type) (llvm.Type, error) {
|
|||
panic(fmt.Sprintln("generator doesn't know about type", ty))
|
||||
}
|
||||
}
|
||||
|
||||
func (this *generator) generateTypeIndex () (*llvm.TypeInt, error) {
|
||||
sizeTypeAny, err := this.typedef("Index")
|
||||
if err != nil { return nil, err }
|
||||
return sizeTypeAny.(*llvm.TypeInt), nil
|
||||
}
|
||||
|
|
|
@ -6,8 +6,19 @@ import "strings"
|
|||
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||
|
||||
func (this *generator) generateTypeIndex () (*llvm.TypeInt, error) {
|
||||
ty, err := this.typedef(entity.Key {
|
||||
Name: "Index",
|
||||
})
|
||||
if err != nil { return nil, err }
|
||||
return ty.(*llvm.TypeInt), nil
|
||||
}
|
||||
|
||||
func (this *generator) generateTypeNamed (ty *entity.TypeNamed) (llvm.Type, error) {
|
||||
underlying, err := this.typedef(ty.Name)
|
||||
underlying, err := this.typedef(entity.Key {
|
||||
Unit: ty.Type.Unit(),
|
||||
Name: ty.Name,
|
||||
})
|
||||
if err != nil { return nil, err }
|
||||
return &llvm.TypeDefined { Source: underlying }, nil
|
||||
}
|
||||
|
@ -17,7 +28,7 @@ func (this *generator) generateTypePointer (ty *entity.TypePointer) (llvm.Type,
|
|||
}
|
||||
|
||||
func (this *generator) generateTypeSlice (ty *entity.TypeSlice) (llvm.Type, error) {
|
||||
indexType, err := this.typedef("Index")
|
||||
indexType, err := this.generateTypeIndex()
|
||||
if err != nil { return nil, err }
|
||||
return &llvm.TypeStruct {
|
||||
Fields: []llvm.Type {
|
||||
|
|
Loading…
Reference in New Issue