Move compileAssignmentExpressionWAT into compileAssignmentUpdateExpressionWAT
This commit is contained in:
parent
9e39936842
commit
d8a80de37c
145
backend_wat.go
145
backend_wat.go
@ -214,12 +214,9 @@ func castPrimitiveWAT(from PrimitiveType, to PrimitiveType) (Code, error) {
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpression) (Code, error) {
|
||||
lhs := assignment.Lhs
|
||||
|
||||
exprWAT, err := c.compileExpressionWAT(assignment.Value)
|
||||
if err != nil {
|
||||
return emptyCode(), err
|
||||
func (c *Compiler) compileAssignmentUpdateExpressionWAT(lhs Expression, update bool, valueOrUpdateWAT Code, evaluateToOldValue bool) (Code, error) {
|
||||
if !isValidLHS(lhs.Type) {
|
||||
panic(fmt.Sprintf("invalid LHS type passed to compileAssignmentUpdateExpressionWAT(): %s", lhs.Type))
|
||||
}
|
||||
|
||||
switch lhs.Type {
|
||||
@ -227,10 +224,40 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
||||
ref := lhs.Value.(VariableReferenceExpression)
|
||||
local := strconv.Itoa(getLocal(c.CurrentBlock, ref.Variable).Index)
|
||||
|
||||
exprWAT.add("local.tee $" + local + " (;" + ref.Variable + ";)")
|
||||
return exprWAT, nil
|
||||
code := emptyCode()
|
||||
|
||||
// Load variable
|
||||
if update || evaluateToOldValue {
|
||||
exprWAT, err := c.compileExpressionWAT(lhs)
|
||||
if err != nil {
|
||||
return emptyCode(), err
|
||||
}
|
||||
|
||||
code.addAll(exprWAT)
|
||||
}
|
||||
|
||||
var tmpLocal Local
|
||||
if update && evaluateToOldValue {
|
||||
tmpLocal = Local{Name: "", Type: *lhs.ValueType, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, tmpLocal)
|
||||
|
||||
// dup old value
|
||||
code.add("local.tee $" + strconv.Itoa(tmpLocal.Index))
|
||||
code.add("local.get $" + strconv.Itoa(tmpLocal.Index))
|
||||
}
|
||||
|
||||
code.addAll(valueOrUpdateWAT)
|
||||
|
||||
if evaluateToOldValue {
|
||||
code.add("local.set $" + local + " (;" + ref.Variable + ";)")
|
||||
} else {
|
||||
code.add("local.tee $" + local + " (;" + ref.Variable + ";)")
|
||||
}
|
||||
|
||||
return code, nil
|
||||
case Expression_ArrayAccess:
|
||||
array := lhs.Value.(ArrayAccessExpression)
|
||||
elementType := array.Array.ValueType.Value.(ArrayType).ElementType
|
||||
|
||||
localArray := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType(), Position: unknownPosition()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localArray)
|
||||
@ -238,7 +265,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
||||
localIndex := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType(), Position: unknownPosition()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localIndex)
|
||||
|
||||
localElement := Local{Name: "", Type: *assignment.Value.ValueType, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
localElement := Local{Name: "", Type: elementType, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localElement)
|
||||
|
||||
arrayWAT, err := c.compileExpressionWAT(array.Array)
|
||||
@ -270,6 +297,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
||||
// Error if index < 0
|
||||
wat.add(
|
||||
"block",
|
||||
"(;bounds check < 0;)",
|
||||
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
|
||||
c.getAddressWATType()+".const 0",
|
||||
c.getAddressWATType()+".ge_s",
|
||||
@ -281,6 +309,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
||||
// Error if index >= array length
|
||||
wat.add(
|
||||
"block",
|
||||
"(;bounds check >= array length;)",
|
||||
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
|
||||
"local.get $"+strconv.Itoa(localArray.Index)+" (;array base address;)",
|
||||
"i32.load", // Load array length
|
||||
@ -291,7 +320,6 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
||||
)
|
||||
}
|
||||
|
||||
elementType := array.Array.ValueType.Value.(ArrayType).ElementType
|
||||
wat.add(
|
||||
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
|
||||
c.getAddressWATType()+".const "+strconv.Itoa(c.getTypeSizeBytes(elementType)),
|
||||
@ -302,7 +330,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
||||
c.getAddressWATType()+".add",
|
||||
)
|
||||
|
||||
wat.addAll(exprWAT)
|
||||
wat.addAll(valueOrUpdateWAT)
|
||||
|
||||
wat.add(
|
||||
"local.tee $"+strconv.Itoa(localElement.Index),
|
||||
@ -314,63 +342,6 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
||||
case Expression_RawMemoryReference:
|
||||
raw := lhs.Value.(RawMemoryReferenceExpression)
|
||||
|
||||
local := Local{Name: "", Type: *lhs.ValueType, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, local)
|
||||
|
||||
if raw.Type.Type != Type_Primitive {
|
||||
panic("TODO") //TODO
|
||||
}
|
||||
|
||||
addrWAT, err := c.compileExpressionWAT(raw.Address)
|
||||
if err != nil {
|
||||
return emptyCode(), err
|
||||
}
|
||||
|
||||
// TODO: should leave a copy of the stored value on the stack
|
||||
code := addrWAT.clone()
|
||||
code.addAll(exprWAT)
|
||||
code.add(
|
||||
"local.tee $"+strconv.Itoa(local.Index),
|
||||
c.getWATType(raw.Type)+".store",
|
||||
"local.get $"+strconv.Itoa(local.Index),
|
||||
)
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
||||
panic("assignment expr not implemented")
|
||||
}
|
||||
|
||||
func (c *Compiler) compileAssignmentUpdateExpressionWAT(lhs Expression, updateWAT Code, evaluateToOldValue bool) (Code, error) {
|
||||
switch lhs.Type {
|
||||
case Expression_VariableReference:
|
||||
ref := lhs.Value.(VariableReferenceExpression)
|
||||
local := strconv.Itoa(getLocal(c.CurrentBlock, ref.Variable).Index)
|
||||
|
||||
exprWAT, err := c.compileExpressionWAT(lhs)
|
||||
if err != nil {
|
||||
return emptyCode(), err
|
||||
}
|
||||
|
||||
wat := exprWAT.clone()
|
||||
if evaluateToOldValue {
|
||||
wat.add("local.get $" + local + " (;" + ref.Variable + ";)")
|
||||
}
|
||||
|
||||
wat.addAll(updateWAT)
|
||||
|
||||
if evaluateToOldValue {
|
||||
wat.add("local.set $" + local + " (;" + ref.Variable + ";)")
|
||||
} else {
|
||||
wat.add("local.tee $" + local + " (;" + ref.Variable + ";)")
|
||||
}
|
||||
|
||||
return wat, nil
|
||||
case Expression_ArrayAccess:
|
||||
panic("TODO") // TODO
|
||||
case Expression_RawMemoryReference:
|
||||
raw := lhs.Value.(RawMemoryReferenceExpression)
|
||||
|
||||
localAddress := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localAddress)
|
||||
|
||||
@ -388,27 +359,29 @@ func (c *Compiler) compileAssignmentUpdateExpressionWAT(lhs Expression, updateWA
|
||||
|
||||
wat := addrWAT
|
||||
|
||||
// dup address
|
||||
wat.add(
|
||||
"local.tee $"+strconv.Itoa(localAddress.Index),
|
||||
"local.get $"+strconv.Itoa(localAddress.Index),
|
||||
)
|
||||
if update {
|
||||
// dup address
|
||||
wat.add(
|
||||
"local.tee $"+strconv.Itoa(localAddress.Index)+" (;address;)",
|
||||
"local.get $"+strconv.Itoa(localAddress.Index)+" (;address;)",
|
||||
)
|
||||
|
||||
wat.add(c.getWATType(raw.Type) + ".load")
|
||||
|
||||
if evaluateToOldValue {
|
||||
wat.add("local.tee $" + strconv.Itoa(localValue.Index))
|
||||
wat.add(c.getWATType(raw.Type) + ".load")
|
||||
}
|
||||
|
||||
wat.addAll(updateWAT)
|
||||
if evaluateToOldValue {
|
||||
wat.add("local.tee $" + strconv.Itoa(localValue.Index) + " (;temp storage for value;)")
|
||||
}
|
||||
|
||||
wat.addAll(valueOrUpdateWAT)
|
||||
|
||||
if !evaluateToOldValue {
|
||||
wat.add("local.tee $" + strconv.Itoa(localValue.Index))
|
||||
wat.add("local.tee $" + strconv.Itoa(localValue.Index) + " (;temp storage for value;)")
|
||||
}
|
||||
|
||||
wat.add(
|
||||
c.getWATType(raw.Type)+".store",
|
||||
"local.get $"+strconv.Itoa(localValue.Index),
|
||||
"local.get $"+strconv.Itoa(localValue.Index)+" (;temp storage for value;)",
|
||||
)
|
||||
|
||||
return wat, nil
|
||||
@ -424,10 +397,6 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (Code, error) {
|
||||
case Expression_Assignment:
|
||||
ass := expr.Value.(AssignmentExpression)
|
||||
|
||||
if ass.Operation == Operation_Nop {
|
||||
return c.compileAssignmentExpressionWAT(ass)
|
||||
}
|
||||
|
||||
watRight, err := c.compileExpressionWAT(ass.Value)
|
||||
if err != nil {
|
||||
return emptyCode(), err
|
||||
@ -436,7 +405,7 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (Code, error) {
|
||||
updateOp := c.compileOperationWAT(ass.Operation, ass.Lhs.ValueType.Value.(PrimitiveType))
|
||||
watRight.addAll(updateOp)
|
||||
|
||||
return c.compileAssignmentUpdateExpressionWAT(ass.Lhs, watRight, false)
|
||||
return c.compileAssignmentUpdateExpressionWAT(ass.Lhs, ass.Operation != Operation_Nop, watRight, false)
|
||||
case Expression_Literal:
|
||||
lit := expr.Value.(LiteralExpression)
|
||||
switch lit.Literal.Type {
|
||||
@ -600,7 +569,7 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (Code, error) {
|
||||
updateWAT.add(valueType + ".sub")
|
||||
}
|
||||
|
||||
return c.compileAssignmentUpdateExpressionWAT(unary.Value, updateWAT, unary.Operation == UnaryOperation_PostIncrement || unary.Operation == UnaryOperation_PostDecrement)
|
||||
return c.compileAssignmentUpdateExpressionWAT(unary.Value, true, updateWAT, unary.Operation == UnaryOperation_PostIncrement || unary.Operation == UnaryOperation_PostDecrement)
|
||||
}
|
||||
case Expression_Cast:
|
||||
cast := expr.Value.(CastExpression)
|
||||
@ -721,6 +690,8 @@ func (c *Compiler) compileOperationWAT(operation Operation, operandType Primitiv
|
||||
}
|
||||
|
||||
switch operation {
|
||||
case Operation_Nop:
|
||||
return emptyCode()
|
||||
case Operation_Add:
|
||||
op = getPrimitiveWATType(operandType) + ".add"
|
||||
case Operation_Sub:
|
||||
@ -768,7 +739,7 @@ func (c *Compiler) compileStatementWAT(stmt Statement, block *Block) (Code, erro
|
||||
}
|
||||
}
|
||||
|
||||
for _ = range numItems {
|
||||
for range numItems {
|
||||
wat.add("drop")
|
||||
}
|
||||
|
||||
|
13
types.go
13
types.go
@ -128,6 +128,10 @@ func (t PrimitiveType) String() string {
|
||||
return getPrimitiveTypeName(t)
|
||||
}
|
||||
|
||||
func (t ExpressionType) String() string {
|
||||
return strconv.Itoa(int(t))
|
||||
}
|
||||
|
||||
func getOperation(operator Operator) Operation {
|
||||
switch operator {
|
||||
case Operator_Greater:
|
||||
@ -186,3 +190,12 @@ func isBooleanOperation(operation Operation) bool {
|
||||
func isArithmeticOperation(operation Operation) bool {
|
||||
return !isBooleanOperation(operation)
|
||||
}
|
||||
|
||||
func isValidLHS(expressionType ExpressionType) bool {
|
||||
switch expressionType {
|
||||
case Expression_ArrayAccess, Expression_VariableReference, Expression_RawMemoryReference:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user