More unary expressions

This commit is contained in:
MrLetsplay 2024-04-09 13:57:17 +02:00
parent 45f5ea3398
commit 0236dfbb2d
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
7 changed files with 114 additions and 53 deletions

View File

@ -323,23 +323,35 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (string, error) {
} }
return wat + "call $" + fc.Function + "\n", nil return wat + "call $" + fc.Function + "\n", nil
case Expression_Negate: case Expression_Unary:
neg := expr.Value.(NegateExpression) unary := expr.Value.(UnaryExpression)
exprType := expr.ValueType.Value.(PrimitiveType) exprType := expr.ValueType.Value.(PrimitiveType)
wat, err := c.compileExpressionWAT(neg.Value) wat, err := c.compileExpressionWAT(unary.Value)
if err != nil { if err != nil {
return "", err return "", err
} }
watType := getPrimitiveWATType(exprType) watType := getPrimitiveWATType(exprType)
if isSignedInt(exprType) || isUnsignedInt(exprType) { switch unary.Operation {
return watType + ".const 0\n" + wat + watType + ".sub\n", nil case UnaryOperation_Negate:
if isFloatingPoint(exprType) {
return wat + watType + ".neg\n", nil
} else {
return watType + ".const 0\n" + wat + watType + ".sub\n" + getTypeCast(exprType), nil
}
case UnaryOperation_Nop:
return wat, nil
case UnaryOperation_BitwiseNot:
if getBits(exprType) == 64 {
return wat + watType + ".const 0xFFFFFFFFFFFFFFFF\n" + watType + ".xor\n" + getTypeCast(exprType), nil
} else {
return wat + watType + ".const 0xFFFFFFFF\n" + watType + ".xor\n" + getTypeCast(exprType), nil
}
case UnaryOperation_LogicalNot:
return wat + "i32.eqz\n", nil
} }
if isFloatingPoint(exprType) {
return watType + ".neg\n", nil
}
case Expression_Cast: case Expression_Cast:
cast := expr.Value.(CastExpression) cast := expr.Value.(CastExpression)

View File

@ -6,3 +6,17 @@ u32 c(u32 n) {
} }
return sum; return sum;
} }
u64 fib(u64 i) {
u64 fibA = 0u64;
u64 fibB = 1u64;
while((i -= 1u64) > 0u64) {
u64 tmp = fibB;
fibB = fibA + fibB;
fibA = tmp;
}
return fibA;
}

View File

@ -55,7 +55,7 @@ const (
type Operator uint32 type Operator uint32
var Operators []string = []string{"=", ">", "<", "!", "+", "-", "*", "/", "%", "==", ">=", "<=", "!=", "+=", "-=", "*=", "/=", "%="} var Operators []string = []string{"=", ">", "<", "!", "+", "-", "*", "/", "%", "==", ">=", "<=", "!=", "+=", "-=", "*=", "/=", "%=", "++", "--", "~"}
const ( const (
Operator_Equals Operator = iota Operator_Equals Operator = iota
@ -76,6 +76,9 @@ const (
Operator_MultiplyEquals Operator_MultiplyEquals
Operator_DivideEquals Operator_DivideEquals
Operator_ModuloEquals Operator_ModuloEquals
Operator_PlusPlus
Operator_MinusMinus
Operator_BitwiseNot
) )
type LiteralType uint32 type LiteralType uint32

View File

@ -87,7 +87,7 @@ const (
Expression_Binary Expression_Binary
Expression_Tuple Expression_Tuple
Expression_FunctionCall Expression_FunctionCall
Expression_Negate Expression_Unary
Expression_ArrayAccess Expression_ArrayAccess
Expression_RawMemoryReference Expression_RawMemoryReference
Expression_Cast Expression_Cast
@ -125,11 +125,19 @@ const (
Operation_Less Operation_Less
Operation_GreaterEquals Operation_GreaterEquals
Operation_LessEquals Operation_LessEquals
Operation_LogicalNot
Operation_NotEquals Operation_NotEquals
Operation_Equals Operation_Equals
) )
type UnaryOperation uint32
const (
UnaryOperation_Negate UnaryOperation = iota
UnaryOperation_Nop
UnaryOperation_BitwiseNot
UnaryOperation_LogicalNot
)
type BinaryExpression struct { type BinaryExpression struct {
Operation Operation Operation Operation
Left Expression Left Expression
@ -145,8 +153,9 @@ type FunctionCallExpression struct {
Parameters *Expression Parameters *Expression
} }
type NegateExpression struct { type UnaryExpression struct {
Value Expression Operation UnaryOperation
Value Expression
} }
type ArrayAccessExpression struct { type ArrayAccessExpression struct {
@ -594,27 +603,27 @@ func (p *Parser) tryUnaryExpression() (*Expression, error) {
return nil, nil return nil, nil
} }
if token.Type == Type_Operator { op, err := pCopy.tryOperator(Operator_Minus, Operator_Plus, Operator_BitwiseNot, Operator_Not)
op := token.Value.(Operator) if err != nil {
if op == Operator_Minus || op == Operator_Plus { return nil, err
pCopy.nextToken()
expr, err := pCopy.tryPrimaryExpression()
if err != nil {
return nil, err
}
if expr == nil {
return nil, nil
}
if op == Operator_Minus {
expr = &Expression{Type: Expression_Negate, Value: NegateExpression{Value: *expr}, Position: token.Position}
}
return expr, nil
}
} }
if op != nil {
expr, err := pCopy.tryPrimaryExpression()
if err != nil {
return nil, err
}
if expr == nil {
return nil, nil
}
*p = pCopy
return &Expression{Type: Expression_Unary, Value: UnaryExpression{Operation: getUnaryOperation(*op), Value: *expr}, Position: token.Position}, nil
}
// TODO: pre-/postfix in-/decrement expr
return p.tryPrimaryExpression() return p.tryPrimaryExpression()
} }
@ -647,7 +656,12 @@ func (p *Parser) tryBinaryExpression0(opFunc func() (*Expression, error), operat
return nil, p.error("expected expression") return nil, p.error("expected expression")
} }
left = &Expression{Type: Expression_Binary, Value: BinaryExpression{Operation: getOperation(*op), Left: *left, Right: *right}, Position: left.Position} operation := getOperation(*op)
if operation == InvalidValue {
return nil, p.error("operator not allowed in binary expression")
}
left = &Expression{Type: Expression_Binary, Value: BinaryExpression{Operation: operation, Left: *left, Right: *right}, Position: left.Position}
} }
} }
@ -679,11 +693,7 @@ func (p *Parser) tryAssignmentExpression() (*Expression, error) {
return nil, err return nil, err
} }
if lhs == nil { if lhs == nil || (lhs.Type != Expression_VariableReference && lhs.Type != Expression_ArrayAccess && lhs.Type != Expression_RawMemoryReference) {
return nil, nil
}
if lhs.Type != Expression_VariableReference && lhs.Type != Expression_ArrayAccess && lhs.Type != Expression_RawMemoryReference {
return p.tryBinaryExpression() return p.tryBinaryExpression()
} }

View File

@ -1,9 +1,6 @@
module alloc; module alloc;
u64 alloc(u64 size) { u64 alloc(u64 size) {
u64 ptr = 0x0u64;
raw(i32, ptr) = 0x03u32;
i32 sus = raw(i32, ptr);
return 0u64; return 0u64;
} }

View File

@ -154,8 +154,6 @@ func getOperation(operator Operator) Operation {
return Operation_Greater return Operation_Greater
case Operator_Less: case Operator_Less:
return Operation_Less return Operation_Less
case Operator_Not:
return Operation_LogicalNot
case Operator_Plus, Operator_PlusEquals: case Operator_Plus, Operator_PlusEquals:
return Operation_Add return Operation_Add
case Operator_Minus, Operator_MinusEquals: case Operator_Minus, Operator_MinusEquals:
@ -179,9 +177,24 @@ func getOperation(operator Operator) Operation {
} }
} }
func getUnaryOperation(operator Operator) UnaryOperation {
switch operator {
case Operator_Minus:
return UnaryOperation_Negate
case Operator_Plus:
return UnaryOperation_Nop
case Operator_BitwiseNot:
return UnaryOperation_BitwiseNot
case Operator_Not:
return UnaryOperation_LogicalNot
default:
return InvalidValue
}
}
func isBooleanOperation(operation Operation) bool { func isBooleanOperation(operation Operation) bool {
switch operation { switch operation {
case Operation_Greater, Operation_Less, Operation_LogicalNot, Operation_Equals, Operation_GreaterEquals, Operation_LessEquals, Operation_NotEquals: case Operation_Greater, Operation_Less, Operation_Equals, Operation_GreaterEquals, Operation_LessEquals, Operation_NotEquals:
return true return true
default: default:
return false return false

View File

@ -156,7 +156,7 @@ func (v *Validator) getArithmeticResultType(expr *Expression, left PrimitiveType
return left, nil return left, nil
} }
return InvalidValue, v.createError(fmt.Sprintf("cannot use the types [%s, %s] in an arithmetic expression without an explicit cast", left, right), expr.Position) // TODO: include type names in error return InvalidValue, v.createError(fmt.Sprintf("cannot use the types [%s, %s] in an arithmetic expression without an explicit cast", left, right), expr.Position)
} }
func getLocal(block *Block, variable string) *Local { func getLocal(block *Block, variable string) *Local {
@ -324,24 +324,36 @@ func (v *Validator) validatePotentiallyVoidExpression(expr *Expression) []error
} }
} }
// TODO: get function and validate using return type
expr.ValueType = calledFunc.ReturnType expr.ValueType = calledFunc.ReturnType
expr.Value = fc expr.Value = fc
case Expression_Negate: case Expression_Unary:
neg := expr.Value.(NegateExpression) unary := expr.Value.(UnaryExpression)
valErrors := v.validateExpression(&neg.Value) valErrors := v.validateExpression(&unary.Value)
if len(valErrors) != 0 { if len(valErrors) != 0 {
errors = append(errors, valErrors...) errors = append(errors, valErrors...)
return errors return errors
} }
if neg.Value.ValueType.Type != Type_Primitive { if unary.Value.ValueType.Type != Type_Primitive {
errors = append(errors, v.createError("cannot negate non-number types", expr.Position)) errors = append(errors, v.createError("cannot operate on non-primitive types", expr.Position))
} else {
primitive := unary.Value.ValueType.Value.(PrimitiveType)
if (unary.Operation == UnaryOperation_Negate || unary.Operation == UnaryOperation_Nop /* + sign */) && !isSignedInt(primitive) && !isFloatingPoint(primitive) {
errors = append(errors, v.createError("can only perform negation/unary plus on signed types", expr.Position))
}
if unary.Operation == UnaryOperation_LogicalNot && primitive != Primitive_Bool {
errors = append(errors, v.createError("cannot perform logical not on non-bool type", expr.Position))
}
if unary.Operation == UnaryOperation_BitwiseNot && !isUnsignedInt(primitive) && !isSignedInt(primitive) {
errors = append(errors, v.createError("cannot perform bitwise not on non-integer type", expr.Position))
}
} }
expr.ValueType = neg.Value.ValueType expr.ValueType = unary.Value.ValueType
expr.Value = neg expr.Value = unary
case Expression_RawMemoryReference: case Expression_RawMemoryReference:
raw := expr.Value.(RawMemoryReferenceExpression) raw := expr.Value.(RawMemoryReferenceExpression)