2023-11-21 20:04:22 +00:00
|
|
|
package generator
|
|
|
|
|
|
|
|
import "fmt"
|
2023-11-23 01:37:37 +00:00
|
|
|
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
2023-11-21 20:04:22 +00:00
|
|
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
|
|
|
|
2024-01-27 10:43:27 +00:00
|
|
|
type ResultMode int; const (
|
|
|
|
ResultModeAny ResultMode = iota
|
|
|
|
ResultModeVal
|
|
|
|
ResultModeLoc
|
|
|
|
)
|
|
|
|
|
2024-01-27 17:11:44 +00:00
|
|
|
func (mode ResultMode) String () string {
|
|
|
|
switch(mode) {
|
|
|
|
case ResultModeAny: return "ResultModeLoc"
|
|
|
|
case ResultModeVal: return "ResultModeVal"
|
|
|
|
case ResultModeLoc: return "ResultModeAny"
|
|
|
|
default: return fmt.Sprintf("ResultMode(%d)", mode)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-26 09:02:22 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-01-27 17:33:15 +00:00
|
|
|
func (this *generator) generateExpression (
|
2024-01-27 10:43:27 +00:00
|
|
|
expression entity.Expression,
|
|
|
|
mode ResultMode,
|
|
|
|
) (
|
|
|
|
register llvm.Value,
|
|
|
|
location bool,
|
|
|
|
err error,
|
|
|
|
) {
|
|
|
|
switch mode {
|
|
|
|
case ResultModeAny:
|
2024-01-27 17:24:47 +00:00
|
|
|
return this.generateExpressionAny(expression)
|
2024-01-27 10:43:27 +00:00
|
|
|
case ResultModeVal:
|
|
|
|
val, err := this.generateExpressionVal(expression)
|
|
|
|
return val, false, err
|
|
|
|
case ResultModeLoc:
|
|
|
|
loc, err := this.generateExpressionLoc(expression)
|
|
|
|
return loc, true, err
|
|
|
|
default: panic("unknown ResultMode")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-27 08:48:00 +00:00
|
|
|
// generateExpression generates an expression and either returns a register
|
|
|
|
// representing the result, or a register containing the location of the result,
|
|
|
|
// whichever will generate the least IR. In the latter case, the boolean
|
|
|
|
// "location" will be true.
|
2024-01-27 17:24:47 +00:00
|
|
|
func (this *generator) generateExpressionAny (expression entity.Expression) (register llvm.Value, location bool, err error) {
|
2024-01-27 09:18:41 +00:00
|
|
|
switch expression := expression.(type) {
|
|
|
|
// these give us an address
|
2024-01-27 08:48:00 +00:00
|
|
|
case *entity.Dereference,
|
|
|
|
*entity.MemberAccess,
|
|
|
|
*entity.Slice,
|
|
|
|
*entity.Subscript,
|
|
|
|
*entity.LiteralArray,
|
|
|
|
*entity.LiteralString,
|
2024-01-27 09:18:41 +00:00
|
|
|
*entity.LiteralStruct,
|
|
|
|
*entity.Variable,
|
2024-01-27 10:43:27 +00:00
|
|
|
*entity.Declaration,
|
|
|
|
*entity.IfElse,
|
|
|
|
*entity.Loop:
|
2024-01-27 08:48:00 +00:00
|
|
|
|
|
|
|
pointer, err := this.generateExpressionLoc(expression)
|
|
|
|
return pointer, true, err
|
|
|
|
|
|
|
|
// these give us a value
|
|
|
|
case *entity.Call,
|
|
|
|
*entity.MethodCall,
|
|
|
|
*entity.Reference,
|
|
|
|
*entity.Length,
|
|
|
|
*entity.ValueCast,
|
|
|
|
*entity.BitCast,
|
|
|
|
*entity.Operation,
|
|
|
|
*entity.LiteralInt,
|
|
|
|
*entity.LiteralFloat,
|
|
|
|
*entity.LiteralBoolean,
|
|
|
|
*entity.LiteralNil:
|
|
|
|
|
|
|
|
value, err := this.generateExpressionVal(expression)
|
|
|
|
return value, true, err
|
|
|
|
|
2024-01-27 09:18:41 +00:00
|
|
|
// these are capable of giving us both
|
|
|
|
case *entity.Block:
|
2024-01-27 10:43:27 +00:00
|
|
|
return this.generateBlock(expression, ResultModeAny)
|
2024-01-27 09:18:41 +00:00
|
|
|
|
2024-01-27 08:48:00 +00:00
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf (
|
|
|
|
"BUG: generator doesnt know about expression %v, ty: %T",
|
|
|
|
expression, expression))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-27 08:39:05 +00:00
|
|
|
// generateExpressionVal generates an expression and returns a register
|
2023-11-26 09:02:22 +00:00
|
|
|
// representing the result.
|
2024-01-27 08:39:05 +00:00
|
|
|
func (this *generator) generateExpressionVal (expression entity.Expression) (llvm.Value, error) {
|
2023-11-26 09:02:22 +00:00
|
|
|
// 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,
|
2023-11-29 05:13:54 +00:00
|
|
|
*entity.LiteralString,
|
2024-01-27 19:17:52 +00:00
|
|
|
*entity.LiteralStruct,
|
|
|
|
*entity.Variable,
|
|
|
|
*entity.Declaration:
|
2023-11-26 09:02:22 +00:00
|
|
|
|
|
|
|
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
|
2023-11-21 20:04:22 +00:00
|
|
|
case *entity.Call:
|
2024-01-27 09:09:27 +00:00
|
|
|
return this.generateCallVal(expression)
|
2023-11-21 20:04:22 +00:00
|
|
|
case *entity.MethodCall:
|
2024-01-27 09:09:27 +00:00
|
|
|
return this.generateMethodCallVal(expression)
|
2023-11-26 09:02:22 +00:00
|
|
|
case *entity.Reference:
|
2024-01-27 09:09:27 +00:00
|
|
|
return this.generateReferenceVal(expression)
|
2023-12-04 03:23:04 +00:00
|
|
|
case *entity.Length:
|
2024-01-27 09:09:27 +00:00
|
|
|
return this.generateLengthVal(expression)
|
2023-11-30 07:06:12 +00:00
|
|
|
case *entity.ValueCast:
|
2024-01-27 09:09:27 +00:00
|
|
|
return this.generateValueCastVal(expression)
|
2023-11-30 01:37:56 +00:00
|
|
|
case *entity.BitCast:
|
2024-01-27 09:09:27 +00:00
|
|
|
return this.generateBitCastVal(expression)
|
2023-11-30 07:13:47 +00:00
|
|
|
case *entity.Operation:
|
2024-01-27 09:09:27 +00:00
|
|
|
return this.generateOperationVal(expression)
|
2023-11-21 20:04:22 +00:00
|
|
|
case *entity.Block:
|
2024-01-27 10:43:27 +00:00
|
|
|
loc, _, err := this.generateBlock(expression, ResultModeVal)
|
|
|
|
return loc, err
|
2023-11-26 09:02:22 +00:00
|
|
|
case *entity.IfElse:
|
2024-01-27 10:43:27 +00:00
|
|
|
loc, _, err := this.generateIfElse(expression, ResultModeVal)
|
|
|
|
return loc, err
|
2023-11-26 09:02:22 +00:00
|
|
|
case *entity.Loop:
|
2024-01-27 10:43:27 +00:00
|
|
|
loc, _, err := this.generateLoop(expression, ResultModeVal)
|
|
|
|
return loc, err
|
2023-11-21 20:04:22 +00:00
|
|
|
case *entity.LiteralInt:
|
2023-11-26 09:02:22 +00:00
|
|
|
return this.generateLiteralInt(expression)
|
2023-11-21 20:04:22 +00:00
|
|
|
case *entity.LiteralFloat:
|
2023-11-26 09:02:22 +00:00
|
|
|
return this.generateLiteralFloat(expression)
|
2023-11-21 20:04:22 +00:00
|
|
|
case *entity.LiteralBoolean:
|
2023-11-26 09:02:22 +00:00
|
|
|
return this.generateLiteralBoolean(expression)
|
2023-12-22 04:33:38 +00:00
|
|
|
case *entity.LiteralNil:
|
|
|
|
return this.generateLiteralNil(expression)
|
2024-01-27 17:11:44 +00:00
|
|
|
|
|
|
|
// we get nothing from these
|
|
|
|
case *entity.Break:
|
|
|
|
return this.generateBreak(expression)
|
|
|
|
case *entity.Return:
|
|
|
|
return this.generateReturn(expression)
|
2023-11-21 20:04:22 +00:00
|
|
|
default:
|
2023-11-29 05:13:54 +00:00
|
|
|
panic(fmt.Sprintf (
|
2024-01-27 09:15:39 +00:00
|
|
|
"BUG: generator doesnt know about value expression %v, ty: %T",
|
2023-11-29 05:13:54 +00:00
|
|
|
expression, expression))
|
2023-11-21 20:04:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-26 09:02:22 +00:00
|
|
|
// 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,
|
2023-11-30 07:13:47 +00:00
|
|
|
*entity.Length,
|
2023-11-26 09:02:22 +00:00
|
|
|
*entity.ValueCast,
|
|
|
|
*entity.BitCast,
|
|
|
|
*entity.Operation,
|
|
|
|
*entity.LiteralInt,
|
|
|
|
*entity.LiteralFloat,
|
2023-12-22 04:33:38 +00:00
|
|
|
*entity.LiteralBoolean,
|
2024-01-27 10:43:27 +00:00
|
|
|
*entity.LiteralNil:
|
2023-11-26 09:02:22 +00:00
|
|
|
|
2024-01-27 08:39:05 +00:00
|
|
|
value, err := this.generateExpressionVal(expression)
|
2023-11-26 09:02:22 +00:00
|
|
|
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)
|
2023-12-07 07:48:27 +00:00
|
|
|
case *entity.Declaration:
|
|
|
|
return this.generateDeclarationLoc(expression)
|
2023-11-26 09:02:22 +00:00
|
|
|
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:
|
2024-01-27 10:43:27 +00:00
|
|
|
loc, _, err := this.generateBlock(expression, ResultModeLoc)
|
|
|
|
return loc, err
|
|
|
|
case *entity.IfElse:
|
|
|
|
loc, _, err := this.generateIfElse(expression, ResultModeLoc)
|
|
|
|
return loc, err
|
|
|
|
case *entity.Loop:
|
|
|
|
loc, _, err := this.generateLoop(expression, ResultModeLoc)
|
|
|
|
return loc, err
|
2023-11-26 09:02:22 +00:00
|
|
|
case *entity.LiteralArray:
|
|
|
|
return this.generateLiteralArrayLoc(expression)
|
2023-11-28 06:15:12 +00:00
|
|
|
case *entity.LiteralString:
|
|
|
|
return this.generateLiteralStringLoc(expression)
|
2023-11-26 09:02:22 +00:00
|
|
|
case *entity.LiteralStruct:
|
|
|
|
return this.generateLiteralStructLoc(expression)
|
2024-01-27 17:11:44 +00:00
|
|
|
|
|
|
|
// we get nothing from these
|
|
|
|
case *entity.Break:
|
|
|
|
return this.generateBreak(expression)
|
|
|
|
case *entity.Return:
|
|
|
|
return this.generateReturn(expression)
|
2023-11-26 09:02:22 +00:00
|
|
|
default:
|
2023-11-29 05:13:54 +00:00
|
|
|
panic(fmt.Sprintf (
|
2024-01-27 09:15:39 +00:00
|
|
|
"BUG: generator doesnt know about location expression %v, ty: %T",
|
2023-11-29 05:13:54 +00:00
|
|
|
expression, expression))
|
2023-11-26 09:02:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-27 17:33:15 +00:00
|
|
|
func (this *generator) generateStatement (
|
2024-01-27 10:43:27 +00:00
|
|
|
statement entity.Statement,
|
|
|
|
mode ResultMode,
|
|
|
|
) (
|
|
|
|
register llvm.Value,
|
|
|
|
location bool,
|
|
|
|
err error,
|
|
|
|
) {
|
|
|
|
switch mode {
|
|
|
|
case ResultModeAny:
|
2024-01-27 17:24:47 +00:00
|
|
|
return this.generateStatementAny(statement)
|
2024-01-27 10:43:27 +00:00
|
|
|
case ResultModeVal:
|
|
|
|
val, err := this.generateStatementVal(statement)
|
|
|
|
return val, false, err
|
|
|
|
case ResultModeLoc:
|
|
|
|
loc, err := this.generateStatementLoc(statement)
|
|
|
|
return loc, true, err
|
|
|
|
default: panic("unknown ResultMode")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-27 17:24:47 +00:00
|
|
|
func (this *generator) generateStatementAny (statement entity.Statement) (register llvm.Value, location bool, err error) {
|
2023-12-07 08:04:29 +00:00
|
|
|
switch statement := statement.(type) {
|
|
|
|
case *entity.Assignment:
|
2024-01-27 08:53:29 +00:00
|
|
|
_, err := this.generateAssignment(statement)
|
|
|
|
return nil, false, err
|
|
|
|
case entity.Expression:
|
2024-01-27 17:24:47 +00:00
|
|
|
return this.generateExpressionAny(statement)
|
2024-01-27 08:53:29 +00:00
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf (
|
|
|
|
"BUG: generator doesnt know about statement %v, ty: %T",
|
|
|
|
statement, statement))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *generator) generateStatementVal (statement entity.Statement) (llvm.Value, error) {
|
|
|
|
switch statement := statement.(type) {
|
2024-01-27 17:33:15 +00:00
|
|
|
case *entity.Assignment:
|
|
|
|
_, err := this.generateAssignment(statement)
|
|
|
|
return nil, err
|
2023-12-07 08:04:29 +00:00
|
|
|
case entity.Expression:
|
2024-01-27 08:39:05 +00:00
|
|
|
return this.generateExpressionVal(statement)
|
2023-12-07 08:04:29 +00:00
|
|
|
default:
|
2023-11-29 05:13:54 +00:00
|
|
|
panic(fmt.Sprintf (
|
2024-01-27 09:15:39 +00:00
|
|
|
"BUG: generator doesnt know about value statement %v, ty: %T",
|
2023-11-29 05:13:54 +00:00
|
|
|
statement, statement))
|
2023-11-26 09:02:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-07 08:04:29 +00:00
|
|
|
func (this *generator) generateStatementLoc (statement entity.Statement) (llvm.Value, error) {
|
|
|
|
switch statement := statement.(type) {
|
2024-01-27 17:33:15 +00:00
|
|
|
case *entity.Assignment:
|
|
|
|
_, err := this.generateAssignment(statement)
|
|
|
|
return nil, err
|
2023-12-07 08:04:29 +00:00
|
|
|
case entity.Expression:
|
|
|
|
return this.generateExpressionLoc(statement)
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf (
|
2024-01-27 09:15:39 +00:00
|
|
|
"BUG: generator doesnt know about location statement %v, ty: %T",
|
2023-12-07 08:04:29 +00:00
|
|
|
statement, statement))
|
|
|
|
}
|
|
|
|
}
|