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
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpression) (Code, error) {
|
func (c *Compiler) compileAssignmentUpdateExpressionWAT(lhs Expression, update bool, valueOrUpdateWAT Code, evaluateToOldValue bool) (Code, error) {
|
||||||
lhs := assignment.Lhs
|
if !isValidLHS(lhs.Type) {
|
||||||
|
panic(fmt.Sprintf("invalid LHS type passed to compileAssignmentUpdateExpressionWAT(): %s", lhs.Type))
|
||||||
exprWAT, err := c.compileExpressionWAT(assignment.Value)
|
|
||||||
if err != nil {
|
|
||||||
return emptyCode(), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch lhs.Type {
|
switch lhs.Type {
|
||||||
@ -227,10 +224,40 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
|||||||
ref := lhs.Value.(VariableReferenceExpression)
|
ref := lhs.Value.(VariableReferenceExpression)
|
||||||
local := strconv.Itoa(getLocal(c.CurrentBlock, ref.Variable).Index)
|
local := strconv.Itoa(getLocal(c.CurrentBlock, ref.Variable).Index)
|
||||||
|
|
||||||
exprWAT.add("local.tee $" + local + " (;" + ref.Variable + ";)")
|
code := emptyCode()
|
||||||
return exprWAT, nil
|
|
||||||
|
// 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:
|
case Expression_ArrayAccess:
|
||||||
array := lhs.Value.(ArrayAccessExpression)
|
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)}
|
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)
|
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)}
|
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)
|
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)
|
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localElement)
|
||||||
|
|
||||||
arrayWAT, err := c.compileExpressionWAT(array.Array)
|
arrayWAT, err := c.compileExpressionWAT(array.Array)
|
||||||
@ -270,6 +297,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
|||||||
// Error if index < 0
|
// Error if index < 0
|
||||||
wat.add(
|
wat.add(
|
||||||
"block",
|
"block",
|
||||||
|
"(;bounds check < 0;)",
|
||||||
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
|
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
|
||||||
c.getAddressWATType()+".const 0",
|
c.getAddressWATType()+".const 0",
|
||||||
c.getAddressWATType()+".ge_s",
|
c.getAddressWATType()+".ge_s",
|
||||||
@ -281,6 +309,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
|||||||
// Error if index >= array length
|
// Error if index >= array length
|
||||||
wat.add(
|
wat.add(
|
||||||
"block",
|
"block",
|
||||||
|
"(;bounds check >= array length;)",
|
||||||
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
|
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
|
||||||
"local.get $"+strconv.Itoa(localArray.Index)+" (;array base address;)",
|
"local.get $"+strconv.Itoa(localArray.Index)+" (;array base address;)",
|
||||||
"i32.load", // Load array length
|
"i32.load", // Load array length
|
||||||
@ -291,7 +320,6 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
elementType := array.Array.ValueType.Value.(ArrayType).ElementType
|
|
||||||
wat.add(
|
wat.add(
|
||||||
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
|
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
|
||||||
c.getAddressWATType()+".const "+strconv.Itoa(c.getTypeSizeBytes(elementType)),
|
c.getAddressWATType()+".const "+strconv.Itoa(c.getTypeSizeBytes(elementType)),
|
||||||
@ -302,7 +330,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
|||||||
c.getAddressWATType()+".add",
|
c.getAddressWATType()+".add",
|
||||||
)
|
)
|
||||||
|
|
||||||
wat.addAll(exprWAT)
|
wat.addAll(valueOrUpdateWAT)
|
||||||
|
|
||||||
wat.add(
|
wat.add(
|
||||||
"local.tee $"+strconv.Itoa(localElement.Index),
|
"local.tee $"+strconv.Itoa(localElement.Index),
|
||||||
@ -314,63 +342,6 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
|||||||
case Expression_RawMemoryReference:
|
case Expression_RawMemoryReference:
|
||||||
raw := lhs.Value.(RawMemoryReferenceExpression)
|
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)}
|
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)
|
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localAddress)
|
||||||
|
|
||||||
@ -388,27 +359,29 @@ func (c *Compiler) compileAssignmentUpdateExpressionWAT(lhs Expression, updateWA
|
|||||||
|
|
||||||
wat := addrWAT
|
wat := addrWAT
|
||||||
|
|
||||||
// dup address
|
if update {
|
||||||
wat.add(
|
// dup address
|
||||||
"local.tee $"+strconv.Itoa(localAddress.Index),
|
wat.add(
|
||||||
"local.get $"+strconv.Itoa(localAddress.Index),
|
"local.tee $"+strconv.Itoa(localAddress.Index)+" (;address;)",
|
||||||
)
|
"local.get $"+strconv.Itoa(localAddress.Index)+" (;address;)",
|
||||||
|
)
|
||||||
|
|
||||||
wat.add(c.getWATType(raw.Type) + ".load")
|
wat.add(c.getWATType(raw.Type) + ".load")
|
||||||
|
|
||||||
if evaluateToOldValue {
|
|
||||||
wat.add("local.tee $" + strconv.Itoa(localValue.Index))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wat.addAll(updateWAT)
|
if evaluateToOldValue {
|
||||||
|
wat.add("local.tee $" + strconv.Itoa(localValue.Index) + " (;temp storage for value;)")
|
||||||
|
}
|
||||||
|
|
||||||
|
wat.addAll(valueOrUpdateWAT)
|
||||||
|
|
||||||
if !evaluateToOldValue {
|
if !evaluateToOldValue {
|
||||||
wat.add("local.tee $" + strconv.Itoa(localValue.Index))
|
wat.add("local.tee $" + strconv.Itoa(localValue.Index) + " (;temp storage for value;)")
|
||||||
}
|
}
|
||||||
|
|
||||||
wat.add(
|
wat.add(
|
||||||
c.getWATType(raw.Type)+".store",
|
c.getWATType(raw.Type)+".store",
|
||||||
"local.get $"+strconv.Itoa(localValue.Index),
|
"local.get $"+strconv.Itoa(localValue.Index)+" (;temp storage for value;)",
|
||||||
)
|
)
|
||||||
|
|
||||||
return wat, nil
|
return wat, nil
|
||||||
@ -424,10 +397,6 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (Code, error) {
|
|||||||
case Expression_Assignment:
|
case Expression_Assignment:
|
||||||
ass := expr.Value.(AssignmentExpression)
|
ass := expr.Value.(AssignmentExpression)
|
||||||
|
|
||||||
if ass.Operation == Operation_Nop {
|
|
||||||
return c.compileAssignmentExpressionWAT(ass)
|
|
||||||
}
|
|
||||||
|
|
||||||
watRight, err := c.compileExpressionWAT(ass.Value)
|
watRight, err := c.compileExpressionWAT(ass.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyCode(), err
|
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))
|
updateOp := c.compileOperationWAT(ass.Operation, ass.Lhs.ValueType.Value.(PrimitiveType))
|
||||||
watRight.addAll(updateOp)
|
watRight.addAll(updateOp)
|
||||||
|
|
||||||
return c.compileAssignmentUpdateExpressionWAT(ass.Lhs, watRight, false)
|
return c.compileAssignmentUpdateExpressionWAT(ass.Lhs, ass.Operation != Operation_Nop, watRight, false)
|
||||||
case Expression_Literal:
|
case Expression_Literal:
|
||||||
lit := expr.Value.(LiteralExpression)
|
lit := expr.Value.(LiteralExpression)
|
||||||
switch lit.Literal.Type {
|
switch lit.Literal.Type {
|
||||||
@ -600,7 +569,7 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (Code, error) {
|
|||||||
updateWAT.add(valueType + ".sub")
|
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:
|
case Expression_Cast:
|
||||||
cast := expr.Value.(CastExpression)
|
cast := expr.Value.(CastExpression)
|
||||||
@ -721,6 +690,8 @@ func (c *Compiler) compileOperationWAT(operation Operation, operandType Primitiv
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch operation {
|
switch operation {
|
||||||
|
case Operation_Nop:
|
||||||
|
return emptyCode()
|
||||||
case Operation_Add:
|
case Operation_Add:
|
||||||
op = getPrimitiveWATType(operandType) + ".add"
|
op = getPrimitiveWATType(operandType) + ".add"
|
||||||
case Operation_Sub:
|
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")
|
wat.add("drop")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
types.go
13
types.go
@ -128,6 +128,10 @@ func (t PrimitiveType) String() string {
|
|||||||
return getPrimitiveTypeName(t)
|
return getPrimitiveTypeName(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t ExpressionType) String() string {
|
||||||
|
return strconv.Itoa(int(t))
|
||||||
|
}
|
||||||
|
|
||||||
func getOperation(operator Operator) Operation {
|
func getOperation(operator Operator) Operation {
|
||||||
switch operator {
|
switch operator {
|
||||||
case Operator_Greater:
|
case Operator_Greater:
|
||||||
@ -186,3 +190,12 @@ func isBooleanOperation(operation Operation) bool {
|
|||||||
func isArithmeticOperation(operation Operation) bool {
|
func isArithmeticOperation(operation Operation) bool {
|
||||||
return !isBooleanOperation(operation)
|
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