This should have been way more commits
This commit is contained in:
parent
3a751666ba
commit
aa107072d8
49
generator/assignment.go
Normal file
49
generator/assignment.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package generator
|
||||||
|
|
||||||
|
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||||
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
|
||||||
|
|
||||||
|
func (this *generator) generateAssignment (assignment *entity.Assignment) (llvm.Value, error) {
|
||||||
|
source, err := this.generateAssignmentSource (
|
||||||
|
assignment.Value,
|
||||||
|
assignment.Location.Type())
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
destination, err := this.generateExpressionLoc(assignment.Location)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
this.blockManager.NewStore(source, destination)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateAssignmentSource performs type coercions if necessary, mainly
|
||||||
|
// interface assignment. this should be called instead of generateExpression
|
||||||
|
// when the type to assign to is known.
|
||||||
|
func (this *generator) generateAssignmentSource (
|
||||||
|
from entity.Expression,
|
||||||
|
to entity.Type,
|
||||||
|
) (
|
||||||
|
llvm.Value,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
source, err := this.generateExpression(from)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
ty := analyzer.ReduceToBase(to)
|
||||||
|
|
||||||
|
switch ty := ty.(type) {
|
||||||
|
// case *entity.TypeInterface:
|
||||||
|
// TODO
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
default:
|
||||||
|
ty = ty
|
||||||
|
return source, nil
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,23 @@
|
|||||||
package generator
|
package generator
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
import "errors"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
|
||||||
|
type loopEntry struct {
|
||||||
|
value llvm.Value
|
||||||
|
stub *llvm.Block
|
||||||
|
wantLocation bool
|
||||||
|
}
|
||||||
|
|
||||||
type blockManager struct {
|
type blockManager struct {
|
||||||
*llvm.Block
|
*llvm.Block
|
||||||
generator *generator
|
generator *generator
|
||||||
function *llvm.Function
|
function *llvm.Function
|
||||||
declarations map[*entity.Declaration] llvm.Value
|
declarations map[*entity.Declaration] llvm.Value
|
||||||
|
|
||||||
|
loops []*loopEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *generator) pushBlockManager (function *llvm.Function) *blockManager {
|
func (this *generator) pushBlockManager (function *llvm.Function) *blockManager {
|
||||||
@ -30,25 +40,56 @@ func (this *generator) popBlockManager () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *blockManager) newBlock () *llvm.Block {
|
func (this *blockManager) pushLoop (wantLocation bool) *loopEntry {
|
||||||
if this.Block != nil && len(this.Block.Instructions) == 0 { return nil }
|
entry := &loopEntry { wantLocation: wantLocation }
|
||||||
|
this.loops = append(this.loops, entry)
|
||||||
previous := this.Block
|
return entry
|
||||||
this.Block = this.function.NewBlock("")
|
|
||||||
return previous
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *blockManager) variable (declaration *entity.Declaration) llvm.Value {
|
func (this *blockManager) popLoop () {
|
||||||
return this.declarations[declaration]
|
this.loops = this.loops[:len(this.loops) - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *blockManager) topLoop () *loopEntry {
|
||||||
|
return this.loops[len(this.loops) - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *blockManager) newAllocaFront (element llvm.Type) llvm.Value {
|
||||||
|
alloca := llvm.NewAlloca(element)
|
||||||
|
|
||||||
|
firstBlock := this.function.Blocks[0]
|
||||||
|
if firstBlock.Terminated() {
|
||||||
|
lastIndex := len(firstBlock.Instructions) - 1
|
||||||
|
firstBlock.Instructions = append (
|
||||||
|
firstBlock.Instructions,
|
||||||
|
firstBlock.Instructions[lastIndex])
|
||||||
|
firstBlock.Instructions[lastIndex] = alloca
|
||||||
|
} else {
|
||||||
|
firstBlock.AddInstruction(alloca)
|
||||||
|
}
|
||||||
|
return alloca
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *blockManager) newBlock () *llvm.Block {
|
||||||
|
this.Block = this.function.NewBlock()
|
||||||
|
return this.Block
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *blockManager) variable (declaration *entity.Declaration) (llvm.Value, error) {
|
||||||
|
value, ok := this.declarations[declaration]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New(fmt.Sprintf("declaration of %v does not exist", declaration.Name))
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *blockManager) addDeclaration (declaration *entity.Declaration, initial llvm.Value) error {
|
func (this *blockManager) addDeclaration (declaration *entity.Declaration, initial llvm.Value) error {
|
||||||
ty, err := this.generator.generateType(declaration.Type())
|
ty, err := this.generator.generateType(declaration.Type())
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
location := this.Block.NewAlloca(ty)
|
location := this.newAllocaFront(ty)
|
||||||
this.declarations[declaration] = location
|
this.declarations[declaration] = location
|
||||||
if initial != nil {
|
if initial != nil {
|
||||||
this.Block.NewStore(initial, location)
|
this.NewStore(initial, location)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -4,51 +4,66 @@ import "fmt"
|
|||||||
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
|
||||||
|
func (this *generator) valueToLocation (value llvm.Value) llvm.Value {
|
||||||
|
pointer := this.blockManager.newAllocaFront(value.Type())
|
||||||
|
this.blockManager.NewStore(value, pointer)
|
||||||
|
return pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) locationToValue (pointer llvm.Value, ty entity.Type) (llvm.Value, error) {
|
||||||
|
irType, err := this.generateType(ty)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
return this.blockManager.NewLoad(irType, pointer), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateExpression generates an expression and returns a register
|
||||||
|
// representing the result.
|
||||||
func (this *generator) generateExpression (expression entity.Expression) (llvm.Value, error) {
|
func (this *generator) generateExpression (expression entity.Expression) (llvm.Value, error) {
|
||||||
switch expression.(type) {
|
// we get an address from these, so we need to load the value
|
||||||
|
switch expression := expression.(type) {
|
||||||
|
case *entity.Dereference,
|
||||||
|
*entity.MemberAccess,
|
||||||
|
*entity.Slice,
|
||||||
|
*entity.Subscript,
|
||||||
|
*entity.LiteralArray,
|
||||||
|
*entity.LiteralStruct:
|
||||||
|
|
||||||
|
pointer, err := this.generateExpressionLoc(expression)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
return this.locationToValue(pointer, expression.Type())
|
||||||
|
|
||||||
|
// we get a value from these, so we can return them as-is
|
||||||
case *entity.Variable:
|
case *entity.Variable:
|
||||||
return this.generateVariable(expression.(*entity.Variable))
|
return this.generateVariable(expression)
|
||||||
case *entity.Call:
|
case *entity.Call:
|
||||||
return this.generateCall(expression.(*entity.Call))
|
return this.generateCall(expression)
|
||||||
case *entity.MethodCall:
|
case *entity.MethodCall:
|
||||||
return this.generateMethodCall(expression.(*entity.MethodCall))
|
return this.generateMethodCall(expression)
|
||||||
// case *entity.Subscript:
|
case *entity.Reference:
|
||||||
// return this.generateSubscript(expression.(*entity.Subscript))
|
return this.generateReference(expression)
|
||||||
// case *entity.Slice:
|
|
||||||
// return this.generateSlice(expression.(*entity.Slice))
|
|
||||||
// case *entity.Dereference:
|
|
||||||
// return this.generateDereference(expression.(*entity.Dereference))
|
|
||||||
// case *entity.Reference:
|
|
||||||
// return this.generateReference(expression.(*entity.Reference))
|
|
||||||
// case *entity.ValueCast:
|
// case *entity.ValueCast:
|
||||||
// return this.generateValueCast(expression.(*entity.ValueCast))
|
// return this.generateValueCast(expression)
|
||||||
// case *entity.BitCast:
|
// case *entity.BitCast:
|
||||||
// return this.generateBitCast(expression.(*entity.BitCast))
|
// return this.generateBitCast(expression)
|
||||||
// case *entity.Operation:
|
// case *entity.Operation:
|
||||||
// return this.generateOperation(expression.(*entity.Operation))
|
// return this.generateOperation(expression)
|
||||||
case *entity.Block:
|
case *entity.Block:
|
||||||
return this.generateBlock(expression.(*entity.Block))
|
return this.generateBlock(expression)
|
||||||
// case *entity.MemberAccess:
|
case *entity.IfElse:
|
||||||
// return this.generateMemberAccess(expression.(*entity.MemberAccess))
|
return this.generateIfElse(expression, false)
|
||||||
// case *entity.IfElse:
|
case *entity.Loop:
|
||||||
// return this.generateIfElse(expression.(*entity.IfElse))
|
return this.generateLoop(expression, false)
|
||||||
// case *entity.Loop:
|
case *entity.Break:
|
||||||
// return this.generateLoop(expression.(*entity.Loop))
|
return this.generateBreak(expression)
|
||||||
// case *entity.Break:
|
case *entity.Return:
|
||||||
// return this.generateBreak(expression.(*entity.Break))
|
return this.generateReturn(expression)
|
||||||
// case *entity.Return:
|
|
||||||
// return this.generateReturn(expression.(*entity.Return))
|
|
||||||
|
|
||||||
case *entity.LiteralInt:
|
case *entity.LiteralInt:
|
||||||
return this.generateLiteralInt(expression.(*entity.LiteralInt))
|
return this.generateLiteralInt(expression)
|
||||||
case *entity.LiteralFloat:
|
case *entity.LiteralFloat:
|
||||||
return this.generateLiteralFloat(expression.(*entity.LiteralFloat))
|
return this.generateLiteralFloat(expression)
|
||||||
case *entity.LiteralArray:
|
|
||||||
return this.generateLiteralArray(expression.(*entity.LiteralArray))
|
|
||||||
// case *entity.LiteralStruct:
|
|
||||||
// return this.generateLiteralStruct(expression.(*entity.LiteralStruct))
|
|
||||||
case *entity.LiteralBoolean:
|
case *entity.LiteralBoolean:
|
||||||
return this.generateLiteralBoolean(expression.(*entity.LiteralBoolean))
|
return this.generateLiteralBoolean(expression)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprint (
|
panic(fmt.Sprint (
|
||||||
"BUG: generator doesnt know about expression ",
|
"BUG: generator doesnt know about expression ",
|
||||||
@ -57,9 +72,9 @@ func (this *generator) generateExpression (expression entity.Expression) (llvm.V
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *generator) generateStatement (statement entity.Statement) (llvm.Value, error) {
|
func (this *generator) generateStatement (statement entity.Statement) (llvm.Value, error) {
|
||||||
/*if assignment, ok := statement.(*entity.Assignment); ok {
|
if assignment, ok := statement.(*entity.Assignment); ok {
|
||||||
return this.generateAssignment(assignment)
|
return this.generateAssignment(assignment)
|
||||||
} else*/ if expression, ok := statement.(entity.Expression); ok {
|
} else if expression, ok := statement.(entity.Expression); ok {
|
||||||
return this.generateExpression(expression)
|
return this.generateExpression(expression)
|
||||||
} else {
|
} else {
|
||||||
panic(fmt.Sprint (
|
panic(fmt.Sprint (
|
||||||
@ -67,3 +82,70 @@ func (this *generator) generateStatement (statement entity.Statement) (llvm.Valu
|
|||||||
statement))
|
statement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generateExpressionLoc generates an expression and returns a register
|
||||||
|
// representing the address of the result. This function avoids adding alloca
|
||||||
|
// instructions whenever possible, trying to refer to the original data.
|
||||||
|
func (this *generator) generateExpressionLoc (expression entity.Expression) (llvm.Value, error) {
|
||||||
|
switch expression := expression.(type) {
|
||||||
|
|
||||||
|
// we get a value from these, so we need to store the value and then
|
||||||
|
// return an address to that
|
||||||
|
case *entity.Call,
|
||||||
|
*entity.MethodCall,
|
||||||
|
*entity.Reference,
|
||||||
|
*entity.ValueCast,
|
||||||
|
*entity.BitCast,
|
||||||
|
*entity.Operation,
|
||||||
|
*entity.LiteralInt,
|
||||||
|
*entity.LiteralFloat,
|
||||||
|
*entity.LiteralBoolean:
|
||||||
|
|
||||||
|
value, err := this.generateExpression(expression)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
return this.valueToLocation(value), nil
|
||||||
|
|
||||||
|
// we get an address from these, so we can return them as-is
|
||||||
|
case *entity.Variable:
|
||||||
|
return this.generateVariableLoc(expression)
|
||||||
|
case *entity.Slice:
|
||||||
|
return this.generateSliceLoc(expression)
|
||||||
|
case *entity.Subscript:
|
||||||
|
return this.generateSubscriptLoc(expression)
|
||||||
|
case *entity.Dereference:
|
||||||
|
return this.generateDereferenceLoc(expression)
|
||||||
|
case *entity.MemberAccess:
|
||||||
|
return this.generateMemberAccessLoc(expression)
|
||||||
|
case *entity.Block:
|
||||||
|
return this.generateBlockLoc(expression)
|
||||||
|
case *entity.IfElse:
|
||||||
|
return this.generateIfElse(expression, true)
|
||||||
|
case *entity.Loop:
|
||||||
|
return this.generateLoop(expression, true)
|
||||||
|
case *entity.Break:
|
||||||
|
return this.generateBreak(expression)
|
||||||
|
case *entity.Return:
|
||||||
|
return this.generateReturn(expression)
|
||||||
|
case *entity.LiteralArray:
|
||||||
|
return this.generateLiteralArrayLoc(expression)
|
||||||
|
case *entity.LiteralStruct:
|
||||||
|
return this.generateLiteralStructLoc(expression)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprint (
|
||||||
|
"BUG: generator doesnt know about location expression ",
|
||||||
|
expression))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateStatementLoc (statement entity.Statement) (llvm.Value, error) {
|
||||||
|
if assignment, ok := statement.(*entity.Assignment); ok {
|
||||||
|
return this.generateAssignment(assignment)
|
||||||
|
} else if expression, ok := statement.(entity.Expression); ok {
|
||||||
|
return this.generateExpressionLoc(expression)
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprint (
|
||||||
|
"BUG: generator doesnt know about statement ",
|
||||||
|
statement))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@ import "fmt"
|
|||||||
import "errors"
|
import "errors"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
|
|
||||||
|
|
||||||
func (this *generator) generateVariable (variable *entity.Variable) (llvm.Value, error) {
|
func (this *generator) generateVariable (variable *entity.Variable) (llvm.Value, error) {
|
||||||
value := this.blockManager.variable(variable.Declaration)
|
location, err := this.generateVariableLoc(variable)
|
||||||
|
if err != nil { return nil, err }
|
||||||
irType, err := this.generateType(variable.Type())
|
irType, err := this.generateType(variable.Type())
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
return this.blockManager.NewLoad(irType, value), nil
|
return this.blockManager.NewLoad(irType, location), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *generator) generateCall (call *entity.Call) (llvm.Value, error) {
|
func (this *generator) generateCall (call *entity.Call) (llvm.Value, error) {
|
||||||
@ -19,8 +19,11 @@ func (this *generator) generateCall (call *entity.Call) (llvm.Value, error) {
|
|||||||
|
|
||||||
args := make([]llvm.Value, len(call.Arguments))
|
args := make([]llvm.Value, len(call.Arguments))
|
||||||
for index, argument := range call.Arguments {
|
for index, argument := range call.Arguments {
|
||||||
irArgument, err := this.generateExpression(argument)
|
irArgument, err := this.generateAssignmentSource (
|
||||||
|
argument,
|
||||||
|
call.Function.Signature.Arguments[index].Type())
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
args[index] = irArgument
|
args[index] = irArgument
|
||||||
}
|
}
|
||||||
return this.blockManager.NewCall(function, function.Signature, args...), nil
|
return this.blockManager.NewCall(function, function.Signature, args...), nil
|
||||||
@ -30,10 +33,16 @@ func (this *generator) generateMethodCall (call *entity.MethodCall) (llvm.Value,
|
|||||||
source, err := this.generateExpression(call.Source)
|
source, err := this.generateExpression(call.Source)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
var signature *entity.Signature
|
||||||
|
if call.Method != nil { signature = call.Method.Signature }
|
||||||
|
if call.Behavior != nil { signature = call.Behavior }
|
||||||
|
|
||||||
// build list of args
|
// build list of args
|
||||||
args := make([]llvm.Value, len(call.Arguments) + 1)
|
args := make([]llvm.Value, len(call.Arguments) + 1)
|
||||||
for index, argument := range call.Arguments {
|
for index, argument := range call.Arguments {
|
||||||
irArgument, err := this.generateExpression(argument)
|
irArgument, err := this.generateAssignmentSource (
|
||||||
|
argument,
|
||||||
|
signature.Arguments[index].Type())
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
args[index + 1] = irArgument
|
args[index + 1] = irArgument
|
||||||
}
|
}
|
||||||
@ -96,6 +105,10 @@ func (this *generator) generateMethodCall (call *entity.MethodCall) (llvm.Value,
|
|||||||
return nil, errors.New(fmt.Sprintln("no method", call.Name, "for", call.Source))
|
return nil, errors.New(fmt.Sprintln("no method", call.Name, "for", call.Source))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateReference (reference *entity.Reference) (llvm.Value, error) {
|
||||||
|
return this.generateExpressionLoc(reference.Value)
|
||||||
|
}
|
||||||
|
|
||||||
func (this *generator) generateBlock (block *entity.Block) (llvm.Value, error) {
|
func (this *generator) generateBlock (block *entity.Block) (llvm.Value, error) {
|
||||||
var last llvm.Value
|
var last llvm.Value
|
||||||
var err error
|
var err error
|
||||||
@ -106,80 +119,91 @@ func (this *generator) generateBlock (block *entity.Block) (llvm.Value, error) {
|
|||||||
return last, nil
|
return last, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *generator) generateLiteralInt (literal *entity.LiteralInt) (llvm.Value, error) {
|
func (this *generator) generateIfElse (ifelse *entity.IfElse, loc bool) (llvm.Value, error) {
|
||||||
irType, err := this.generateType(analyzer.ReduceToBase(literal.Type()))
|
condition, err := this.generateExpression(ifelse.Condition)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
return llvm.NewConstInt(irType.(*llvm.TypeInt), int64(literal.Value)), nil
|
previous := this.blockManager.Block
|
||||||
}
|
|
||||||
|
|
||||||
func (this *generator) generateLiteralFloat (literal *entity.LiteralFloat) (llvm.Value, error) {
|
var trueBlock, falseBlock *llvm.Block
|
||||||
irType, err := this.generateType(analyzer.ReduceToBase(literal.Type()))
|
var tru, fals llvm.Value
|
||||||
if err != nil { return nil, err }
|
|
||||||
return llvm.NewConstFloat(irType.(*llvm.TypeFloat), literal.Value), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *generator) generateLiteralArray (literal *entity.LiteralArray) (llvm.Value, error) {
|
trueBlock = this.blockManager.newBlock()
|
||||||
ty := analyzer.ReduceToBase(literal.Type())
|
if loc {
|
||||||
|
tru, err = this.generateExpressionLoc(ifelse.True)
|
||||||
makeData := func (element entity.Type) (llvm.Value, error) {
|
} else {
|
||||||
irArrayType, err := this.generateType(&entity.TypeArray {
|
tru, err = this.generateExpression(ifelse.True)
|
||||||
Element: element,
|
|
||||||
})
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
array := this.blockManager.NewAlloca(irArrayType)
|
|
||||||
for index, element := range literal.Elements {
|
|
||||||
irElement, err := this.generateExpression(element)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
elementPointer := this.blockManager.NewGetElementPtr (
|
|
||||||
irArrayType, array,
|
|
||||||
llvm.NewConstInt(llvm.I32, 0),
|
|
||||||
llvm.NewConstInt(llvm.I32, int64(index)))
|
|
||||||
this.blockManager.NewStore(irElement, elementPointer)
|
|
||||||
}
|
}
|
||||||
return array, nil
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
if ifelse.False != nil {
|
||||||
|
falseBlock = this.blockManager.newBlock()
|
||||||
|
if loc {
|
||||||
|
fals, err = this.generateExpressionLoc(ifelse.False)
|
||||||
|
} else {
|
||||||
|
fals, err = this.generateExpression(ifelse.False)
|
||||||
|
}
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
trueIncoming := &llvm.Incoming {
|
||||||
|
X: tru,
|
||||||
|
Predecessor: trueBlock,
|
||||||
|
}
|
||||||
|
falseIncoming := &llvm.Incoming {
|
||||||
|
X: fals,
|
||||||
|
Predecessor: falseBlock,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ty.(type) {
|
previous.NewCondBr(condition, trueBlock, falseBlock)
|
||||||
case *entity.TypeArray:
|
this.blockManager.newBlock()
|
||||||
ty := ty.(*entity.TypeArray)
|
return this.blockManager.NewPhi(trueIncoming, falseIncoming), nil
|
||||||
return makeData(ty.Element)
|
} else {
|
||||||
|
exitBlock := this.blockManager.newBlock()
|
||||||
case *entity.TypeSlice:
|
falseBlock.NewBr(exitBlock)
|
||||||
ty := ty.(*entity.TypeSlice)
|
previous.NewCondBr(condition, trueBlock, falseBlock)
|
||||||
array, err := makeData(ty.Element)
|
return nil, nil
|
||||||
if err != nil { return nil, err }
|
|
||||||
irType, err := this.generateTypeSlice(ty)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
slice := this.blockManager.NewAlloca(irType)
|
|
||||||
data := this.blockManager.NewGetElementPtr (
|
|
||||||
irType, slice,
|
|
||||||
llvm.NewConstInt(llvm.I32, 0),
|
|
||||||
llvm.NewConstInt(llvm.I32, 0))
|
|
||||||
this.blockManager.NewStore(array, data)
|
|
||||||
length := this.blockManager.NewGetElementPtr (
|
|
||||||
irType, slice,
|
|
||||||
llvm.NewConstInt(llvm.I32, 0),
|
|
||||||
llvm.NewConstInt(llvm.I32, 1))
|
|
||||||
sizeType, err := this.typedef("Size")
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
this.blockManager.NewStore (
|
|
||||||
llvm.NewConstInt (
|
|
||||||
sizeType.(*llvm.TypeInt),
|
|
||||||
int64(len(literal.Elements))),
|
|
||||||
length)
|
|
||||||
return slice, nil
|
|
||||||
|
|
||||||
case *entity.TypePointer:
|
|
||||||
ty := ty.(*entity.TypePointer)
|
|
||||||
array, err := makeData(ty.Referenced)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
return array, nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, errors.New(fmt.Sprintln("array can't be used as ", ty))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *generator) generateLiteralBoolean (literal *entity.LiteralBoolean) (llvm.Value, error) {
|
func (this *generator) generateLoop (loop *entity.Loop, loc bool) (llvm.Value, error) {
|
||||||
return llvm.NewConstBool(bool(*literal.Value)), nil
|
previous := this.blockManager.Block
|
||||||
|
body := this.blockManager.newBlock()
|
||||||
|
previous.NewBr(body)
|
||||||
|
|
||||||
|
loopEntry := this.blockManager.pushLoop(loc)
|
||||||
|
defer this.blockManager.popLoop()
|
||||||
|
|
||||||
|
_, err := this.generateExpression(loop.Body)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
this.blockManager.NewBr(body)
|
||||||
|
exit := this.blockManager.newBlock()
|
||||||
|
|
||||||
|
if loopEntry.stub != nil {
|
||||||
|
loopEntry.stub.NewBr(exit)
|
||||||
|
}
|
||||||
|
return loopEntry.value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateBreak (brk *entity.Break) (llvm.Value, error) {
|
||||||
|
loopEntry := this.blockManager.topLoop()
|
||||||
|
if brk.Value != nil {
|
||||||
|
value, err := this.generateExpression(brk.Value)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
loopEntry.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
loopEntry.stub = this.blockManager.Block
|
||||||
|
this.blockManager.newBlock()
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateReturn (ret *entity.Return) (llvm.Value, error) {
|
||||||
|
if ret.Value == nil {
|
||||||
|
this.blockManager.NewRet(nil)
|
||||||
|
} else {
|
||||||
|
value, err := this.generateExpression(ret.Value)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
this.blockManager.NewRet(value)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,15 @@ testString (test,
|
|||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
[puts string:*Byte]:I32
|
[puts string:*Byte]:I32
|
||||||
[main argc:I32 argv:**Byte]:I32 = {
|
[main] = loop [puts (* 104 111 109 101 10 115 109 101 101 116 0)]
|
||||||
[puts [. argv]]
|
|
||||||
0
|
|
||||||
}
|
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
// [write 1 (* 72 101 108 108 111 114 108 100 0) 7]
|
// [write 1 (* 72 101 108 108 111 114 108 100 0) 7]
|
||||||
|
|
||||||
|
// [puts string:*Byte]:I32
|
||||||
|
// [main argc:I32 argv:**Byte] = {
|
||||||
|
// loop {
|
||||||
|
// [puts (* 100 100 0)]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
106
generator/literal.go
Normal file
106
generator/literal.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
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"
|
||||||
|
|
||||||
|
func (this *generator) generateLiteralInt (literal *entity.LiteralInt) (llvm.Value, error) {
|
||||||
|
irType, err := this.generateType(analyzer.ReduceToBase(literal.Type()))
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
return llvm.NewConstInt(irType.(*llvm.TypeInt), int64(literal.Value)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateLiteralFloat (literal *entity.LiteralFloat) (llvm.Value, error) {
|
||||||
|
irType, err := this.generateType(analyzer.ReduceToBase(literal.Type()))
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
return llvm.NewConstFloat(irType.(*llvm.TypeFloat), literal.Value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateLiteralArrayLoc (literal *entity.LiteralArray) (llvm.Value, error) {
|
||||||
|
ty := analyzer.ReduceToBase(literal.Type())
|
||||||
|
|
||||||
|
makeData := func (elementType entity.Type) (llvm.Value, error) {
|
||||||
|
irArrayType, err := this.generateType(&entity.TypeArray {
|
||||||
|
Element: elementType,
|
||||||
|
Length: len(literal.Elements),
|
||||||
|
})
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
array := this.blockManager.newAllocaFront(irArrayType)
|
||||||
|
for index, element := range literal.Elements {
|
||||||
|
irElement, err := this.generateAssignmentSource (
|
||||||
|
element,
|
||||||
|
elementType)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
elementPointer := this.blockManager.NewGetElementPtr (
|
||||||
|
irArrayType, array,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, int64(index)))
|
||||||
|
this.blockManager.NewStore(irElement, elementPointer)
|
||||||
|
}
|
||||||
|
return array, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ty := ty.(type) {
|
||||||
|
case *entity.TypeArray:
|
||||||
|
return makeData(ty.Element)
|
||||||
|
|
||||||
|
case *entity.TypeSlice:
|
||||||
|
array, err := makeData(ty.Element)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
irType, err := this.generateTypeSlice(ty)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
slice := this.blockManager.newAllocaFront(irType)
|
||||||
|
data := this.blockManager.NewGetElementPtr (
|
||||||
|
irType, slice,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, 0))
|
||||||
|
this.blockManager.NewStore(array, data)
|
||||||
|
length := this.blockManager.NewGetElementPtr (
|
||||||
|
irType, slice,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, 1))
|
||||||
|
sizeType, err := this.typedef("Size")
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
this.blockManager.NewStore (
|
||||||
|
llvm.NewConstInt (
|
||||||
|
sizeType.(*llvm.TypeInt),
|
||||||
|
int64(len(literal.Elements))),
|
||||||
|
length)
|
||||||
|
return slice, nil
|
||||||
|
|
||||||
|
case *entity.TypePointer:
|
||||||
|
array, err := makeData(ty.Referenced)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
return this.valueToLocation(array), nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, errors.New(fmt.Sprintln("array can't be used as ", ty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateLiteralStructLoc (literal *entity.LiteralStruct) (llvm.Value, error) {
|
||||||
|
ty := analyzer.ReduceToBase(literal.Type())
|
||||||
|
irType, err := this.generateType(ty)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
structure := this.blockManager.newAllocaFront(irType)
|
||||||
|
|
||||||
|
for index, member := range literal.Members {
|
||||||
|
irMember, err := this.generateExpression(member.Value)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
elementPointer := this.blockManager.NewGetElementPtr (
|
||||||
|
irType, structure,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, int64(index)))
|
||||||
|
this.blockManager.NewStore(irMember, elementPointer)
|
||||||
|
}
|
||||||
|
|
||||||
|
return structure, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateLiteralBoolean (literal *entity.LiteralBoolean) (llvm.Value, error) {
|
||||||
|
return llvm.NewConstBool(bool(*literal.Value)), nil
|
||||||
|
}
|
190
generator/location-expression.go
Normal file
190
generator/location-expression.go
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
package generator
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||||
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
|
||||||
|
|
||||||
|
func (this *generator) generateVariableLoc (variable *entity.Variable) (llvm.Value, error) {
|
||||||
|
return this.blockManager.variable(variable.Declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateSliceLoc (slice *entity.Slice) (llvm.Value, error) {
|
||||||
|
var err error
|
||||||
|
var start, end, dataAddress llvm.Value
|
||||||
|
var sizeType *llvm.TypeInt; {
|
||||||
|
ty, err := this.typedef("Index")
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
sizeType = ty.(*llvm.TypeInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
if slice.Start == nil {
|
||||||
|
start = llvm.NewConstInt(sizeType, 0)
|
||||||
|
} else {
|
||||||
|
start, err = this.generateExpression(slice.Start)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
}
|
||||||
|
if slice.End != nil {
|
||||||
|
end, err = this.generateExpression(slice.End)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceType := analyzer.ReduceToBase(slice.Slice.Type())
|
||||||
|
switch sourceType := sourceType.(type) {
|
||||||
|
case *entity.TypeSlice:
|
||||||
|
source, err := this.generateExpression(slice.Slice)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
irSourceType, err := this.generateType(sourceType)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
dataAddress = this.blockManager.NewGetElementPtr (
|
||||||
|
irSourceType,
|
||||||
|
source,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, 0))
|
||||||
|
if end == nil {
|
||||||
|
endAddr := this.blockManager.NewGetElementPtr (
|
||||||
|
irSourceType,
|
||||||
|
source,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, 2))
|
||||||
|
end = this.blockManager.NewLoad(sizeType, endAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *entity.TypeArray:
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
destinationType, err := this.generateType(slice.Type())
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
newSlice := this.blockManager.newAllocaFront(destinationType)
|
||||||
|
|
||||||
|
// create new slice descriptor
|
||||||
|
dataAddressFieldAddress := this.blockManager.NewGetElementPtr (
|
||||||
|
destinationType,
|
||||||
|
newSlice,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, 0))
|
||||||
|
startFieldAddress := this.blockManager.NewGetElementPtr (
|
||||||
|
destinationType,
|
||||||
|
newSlice,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, 1))
|
||||||
|
endFieldAddress := this.blockManager.NewGetElementPtr (
|
||||||
|
destinationType,
|
||||||
|
newSlice,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, 2))
|
||||||
|
this.blockManager.NewStore(dataAddressFieldAddress, dataAddress)
|
||||||
|
this.blockManager.NewStore(startFieldAddress, start)
|
||||||
|
this.blockManager.NewStore(endFieldAddress, end)
|
||||||
|
|
||||||
|
return newSlice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateSubscriptLoc (subscript *entity.Subscript) (llvm.Value, error) {
|
||||||
|
var sizeType *llvm.TypeInt; {
|
||||||
|
ty, err := this.typedef("Index")
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
sizeType = ty.(*llvm.TypeInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
source, err := this.generateExpressionLoc(subscript.Slice)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
offset, err := this.generateExpression(subscript.Offset)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
var elementType entity.Type
|
||||||
|
var dataAddress llvm.Value
|
||||||
|
|
||||||
|
sourceType := analyzer.ReduceToBase(subscript.Type())
|
||||||
|
switch sourceType := sourceType.(type) {
|
||||||
|
case *entity.TypeSlice:
|
||||||
|
irSourceType, err := this.generateType(sourceType)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
// add index to slice start
|
||||||
|
startFieldAddress := this.blockManager.NewGetElementPtr (
|
||||||
|
irSourceType,
|
||||||
|
source,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, 1))
|
||||||
|
start := this.blockManager.NewLoad(sizeType, startFieldAddress)
|
||||||
|
offset = this.blockManager.NewAdd(start, offset)
|
||||||
|
|
||||||
|
// get slice element
|
||||||
|
elementType = sourceType.Element
|
||||||
|
dataAddress = this.blockManager.NewGetElementPtr (
|
||||||
|
irSourceType,
|
||||||
|
source,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, 0))
|
||||||
|
|
||||||
|
case *entity.TypeArray:
|
||||||
|
elementType = sourceType.Element
|
||||||
|
dataAddress = source
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprint (
|
||||||
|
"BUG: generator can't subscript expression ",
|
||||||
|
subscript.Slice))
|
||||||
|
}
|
||||||
|
|
||||||
|
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.generateExpression(dereference.Pointer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateMemberAccessLoc (access *entity.MemberAccess) (llvm.Value, error) {
|
||||||
|
source, err := this.generateExpressionLoc(access.Source)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
sourceType := analyzer.ReduceToBase(access.Source.Type()).(*entity.TypeStruct)
|
||||||
|
irSourceType, err := this.generateType(sourceType)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
offset := -1
|
||||||
|
for index, name := range sourceType.MemberOrder {
|
||||||
|
if name == access.Member {
|
||||||
|
offset = index
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.blockManager.NewGetElementPtr (
|
||||||
|
irSourceType,
|
||||||
|
source,
|
||||||
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
|
llvm.NewConstInt(llvm.I32, int64(offset))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *generator) generateBlockLoc (block *entity.Block) (llvm.Value, error) {
|
||||||
|
var last llvm.Value
|
||||||
|
var err error
|
||||||
|
for index, step := range block.Steps {
|
||||||
|
// prefer generating a normal statement to avoid allocations
|
||||||
|
if index == len(block.Steps) - 1 {
|
||||||
|
last, err = this.generateStatementLoc(step)
|
||||||
|
} else {
|
||||||
|
last, err = this.generateStatement(step)
|
||||||
|
}
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
}
|
||||||
|
return last, nil
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ func testReader (test *testing.T, correct string, inputs ...io.Reader) {
|
|||||||
for index, stream := range inputs {
|
for index, stream := range inputs {
|
||||||
err := ast.Parse(fmt.Sprintf("stream%d.fspl", index), stream)
|
err := ast.Parse(fmt.Sprintf("stream%d.fspl", index), stream)
|
||||||
if err != nil && err != io.EOF{
|
if err != nil && err != io.EOF{
|
||||||
test.Error("parser returned error: ", err)
|
test.Error("parser returned error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,19 +24,19 @@ func testReader (test *testing.T, correct string, inputs ...io.Reader) {
|
|||||||
tree := analyzer.Tree { }
|
tree := analyzer.Tree { }
|
||||||
err := tree.Analyze(ast)
|
err := tree.Analyze(ast)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
test.Error("analyzer returned error: ", err)
|
test.Error("analyzer returned error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
module, err := NativeTarget().Generate(tree)
|
module, err := NativeTarget().Generate(tree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
test.Error("generator returned error: ", err)
|
test.Error("generator returned error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
output := new(strings.Builder)
|
output := new(strings.Builder)
|
||||||
_, err = module.WriteTo(output)
|
_, err = module.WriteTo(output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
test.Error("generator returned error: ", err)
|
test.Error("generator returned error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,23 +5,6 @@ import "errors"
|
|||||||
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
|
||||||
// type pointer struct { TypeName string }
|
|
||||||
// func (this *pointer) Name () string { return this.TypeName }
|
|
||||||
// func (this *pointer) SetName (name string) { this.TypeName = name }
|
|
||||||
// func (*pointer) LLString () string { return "ptr" }
|
|
||||||
// func (this *pointer) String () string {
|
|
||||||
// if this.TypeName == "" {
|
|
||||||
// return this.LLString()
|
|
||||||
// } else {
|
|
||||||
// return "%" + this.TypeName
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// func (*pointer) Equal (ty llvm.Type) bool {
|
|
||||||
// _, isGenericPointer := ty.(*pointer)
|
|
||||||
// _, isTypedPointer := ty.(*types.PointerType)
|
|
||||||
// return isGenericPointer || isTypedPointer
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (this *generator) generateTypeNamed (ty *entity.TypeNamed) (llvm.Type, error) {
|
func (this *generator) generateTypeNamed (ty *entity.TypeNamed) (llvm.Type, error) {
|
||||||
return this.typedef(ty.Name)
|
return this.typedef(ty.Name)
|
||||||
}
|
}
|
||||||
@ -31,12 +14,13 @@ func (this *generator) generateTypePointer (ty *entity.TypePointer) (llvm.Type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *generator) generateTypeSlice (ty *entity.TypeSlice) (llvm.Type, error) {
|
func (this *generator) generateTypeSlice (ty *entity.TypeSlice) (llvm.Type, error) {
|
||||||
|
indexType, err := this.typedef("Index")
|
||||||
|
if err != nil { return nil, err }
|
||||||
return &llvm.TypeStruct {
|
return &llvm.TypeStruct {
|
||||||
Fields: []llvm.Type {
|
Fields: []llvm.Type {
|
||||||
/* data */ llvm.Pointer,
|
/* data */ llvm.Pointer,
|
||||||
/* len */ &llvm.TypeInt {
|
/* start */ indexType,
|
||||||
BitSize: this.target.WordSize,
|
/* end */ indexType,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,20 @@ import "testing"
|
|||||||
|
|
||||||
func TestType (test *testing.T) {
|
func TestType (test *testing.T) {
|
||||||
testString (test,
|
testString (test,
|
||||||
`%AllFloats = type { float, double }
|
`%Index = type i64
|
||||||
%Bool = type i8
|
%String = type { ptr, %Index, %Index }
|
||||||
%Byte = type i8
|
|
||||||
%Index = type i64
|
|
||||||
%Rune = type i32
|
|
||||||
%AllInts = type { %Bool, %Byte, %Index, %Rune, i64, i64, i8, i16, i32, i64, i8, i16, i32, i64 }
|
|
||||||
%Path = type { ptr, i64 }
|
|
||||||
%Pegasus = type { ptr, ptr, ptr, ptr, ptr }
|
%Pegasus = type { ptr, ptr, ptr, ptr, ptr }
|
||||||
%Point = type { i64, i64 }
|
%Point = type { i64, i64 }
|
||||||
%Quadrangle = type [4 x %Point]
|
|
||||||
%Rectangle = type { %Point, %Point }
|
%Rectangle = type { %Point, %Point }
|
||||||
%String = type { ptr, i64 }
|
%Bool = type i8
|
||||||
|
%Byte = type i8
|
||||||
|
%Rune = type i32
|
||||||
|
%AllInts = type { %Bool, %Byte, %Index, %Rune, i64, i64, i8, i16, i32, i64, i8, i16, i32, i64 }
|
||||||
|
%AllFloats = type { float, double }
|
||||||
|
%Path = type { ptr, %Index, %Index }
|
||||||
|
%Quadrangle = type [4 x %Point]
|
||||||
|
%AllTypes = type { %String, %Pegasus, %Rectangle, %AllInts, %AllFloats, %Path, %Quadrangle }
|
||||||
|
declare %AllTypes @x()
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
Point: (x:Int y:Int)
|
Point: (x:Int y:Int)
|
||||||
@ -47,5 +49,15 @@ AllFloats: (
|
|||||||
f64:F64)
|
f64:F64)
|
||||||
Path: *:Point
|
Path: *:Point
|
||||||
Quadrangle: 4:Point
|
Quadrangle: 4:Point
|
||||||
|
AllTypes: (
|
||||||
|
string:String
|
||||||
|
pegasus:Pegasus
|
||||||
|
rectangle:Rectangle
|
||||||
|
ints:AllInts
|
||||||
|
floats:AllFloats
|
||||||
|
path:Path
|
||||||
|
quadrangle:Quadrangle
|
||||||
|
)
|
||||||
|
[x]:AllTypes
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user