Added ssa tests
All checks were successful
/ test (push) Successful in 15s

This commit is contained in:
Eduard Urbach 2025-06-30 13:34:15 +02:00
parent 643f17af8e
commit a1f6c66736
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
11 changed files with 221 additions and 33 deletions

View file

@ -36,7 +36,7 @@ func NewFunction(name string, file *fs.File) *Function {
Name: name,
File: file,
UniqueName: fmt.Sprintf("%s.%s", file.Package, name),
Identifiers: make(map[string]ssa.Value),
Identifiers: make(map[string]ssa.Value, 8),
IR: ssa.IR{
Blocks: []*ssa.Block{
{Instructions: make([]ssa.Value, 0, 8)},

View file

@ -8,7 +8,7 @@ import (
"git.urbach.dev/cli/q/src/types"
)
type BinaryOperation struct {
type BinaryOp struct {
Left Value
Right Value
Op token.Kind
@ -16,12 +16,12 @@ type BinaryOperation struct {
Source
}
func (v *BinaryOperation) Dependencies() []Value {
func (v *BinaryOp) Dependencies() []Value {
return []Value{v.Left, v.Right}
}
func (a *BinaryOperation) Equals(v Value) bool {
b, sameType := v.(*BinaryOperation)
func (a *BinaryOp) Equals(v Value) bool {
b, sameType := v.(*BinaryOp)
if !sameType {
return false
@ -38,14 +38,14 @@ func (a *BinaryOperation) Equals(v Value) bool {
return true
}
func (v *BinaryOperation) IsConst() bool {
func (v *BinaryOp) IsConst() bool {
return true
}
func (v *BinaryOperation) String() string {
func (v *BinaryOp) String() string {
return fmt.Sprintf("%s %s %s", v.Left, expression.Operators[v.Op].Symbol, v.Right)
}
func (v *BinaryOperation) Type() types.Type {
func (v *BinaryOp) Type() types.Type {
return v.Left.Type()
}

45
src/ssa/BinaryOp_test.go Normal file
View file

@ -0,0 +1,45 @@
package ssa_test
import (
"testing"
"git.urbach.dev/cli/q/src/ssa"
"git.urbach.dev/cli/q/src/token"
"git.urbach.dev/cli/q/src/types"
"git.urbach.dev/go/assert"
)
func TestBinaryOp(t *testing.T) {
fn := ssa.IR{}
a := fn.AppendInt(1)
b := fn.AppendInt(2)
c := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: a, Right: b})
fn.AddBlock()
d := fn.AppendInt(3)
e := fn.AppendInt(4)
f := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: d, Right: e})
assert.Equal(t, c.String(), "1 + 2")
assert.Equal(t, f.String(), "3 + 4")
assert.True(t, c.Type() == types.AnyInt)
}
func TestBinaryOpEquals(t *testing.T) {
fn := ssa.IR{}
one := fn.AppendInt(1)
two := fn.AppendInt(2)
binOp := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: one, Right: two})
oneDup := fn.AppendInt(1)
twoDup := fn.AppendInt(2)
binOpDup := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: oneDup, Right: twoDup})
binOpDiff := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: oneDup, Right: oneDup})
assert.False(t, one.Equals(two))
assert.False(t, one.Equals(binOp))
assert.True(t, one.Equals(oneDup))
assert.False(t, two.Equals(one))
assert.False(t, two.Equals(binOp))
assert.True(t, two.Equals(twoDup))
assert.False(t, binOp.Equals(binOpDiff))
assert.True(t, binOp.Equals(binOpDup))
}

23
src/ssa/Bytes_test.go Normal file
View file

@ -0,0 +1,23 @@
package ssa_test
import (
"testing"
"git.urbach.dev/cli/q/src/ssa"
"git.urbach.dev/cli/q/src/types"
"git.urbach.dev/go/assert"
)
func TestBytes(t *testing.T) {
fn := ssa.IR{}
hello := fn.Append(&ssa.Bytes{Bytes: []byte("Hello")})
world := fn.Append(&ssa.Bytes{Bytes: []byte("World")})
helloDup := fn.Append(&ssa.Bytes{Bytes: []byte("Hello")})
one := fn.AppendInt(1)
assert.False(t, hello.Equals(world))
assert.False(t, hello.Equals(one))
assert.True(t, hello.Equals(helloDup))
assert.Equal(t, hello.String(), "\"Hello\"")
assert.True(t, types.Is(hello.Type(), types.String))
}

View file

@ -2,6 +2,7 @@ package ssa
import (
"fmt"
"strings"
"git.urbach.dev/cli/q/src/types"
)
@ -27,7 +28,13 @@ func (v *Call) IsConst() bool {
}
func (v *Call) String() string {
return fmt.Sprintf("%s(%v)", v.Arguments[0], v.Arguments[1:])
args := make([]string, 0, len(v.Arguments)-1)
for _, arg := range v.Arguments[1:] {
args = append(args, arg.String())
}
return fmt.Sprintf("%s(%s)", v.Arguments[0].String(), strings.Join(args, ", "))
}
func (v *Call) Type() types.Type {

60
src/ssa/Call_test.go Normal file
View file

@ -0,0 +1,60 @@
package ssa_test
import (
"testing"
"git.urbach.dev/cli/q/src/ssa"
"git.urbach.dev/cli/q/src/types"
"git.urbach.dev/go/assert"
)
func TestCall(t *testing.T) {
fn := ssa.IR{}
myfunc := fn.Append(&ssa.Function{UniqueName: "myfunc", Typ: &types.Function{}})
call := fn.Append(&ssa.Call{Arguments: ssa.Arguments{myfunc}})
one := fn.AppendInt(1)
call2 := fn.Append(&ssa.Call{Arguments: ssa.Arguments{myfunc, one}})
assert.True(t, call.Type() == types.Void)
assert.Equal(t, call.String(), "myfunc()")
assert.Equal(t, call2.String(), "myfunc(1)")
}
func TestCallEquals(t *testing.T) {
fn := ssa.IR{}
sum := fn.Append(&ssa.Function{
UniqueName: "sum",
Typ: &types.Function{
Input: []types.Type{types.Int, types.Int},
Output: []types.Type{types.Int},
},
})
one := fn.AppendInt(1)
two := fn.AppendInt(2)
call1 := fn.Append(&ssa.Call{Arguments: ssa.Arguments{sum, one, two}})
call2 := fn.Append(&ssa.Call{Arguments: ssa.Arguments{sum, one, two}})
assert.False(t, call1.Equals(one))
assert.True(t, call1.Equals(call2))
}
func TestCallReturnType(t *testing.T) {
fn := ssa.IR{}
sum := fn.Append(&ssa.Function{
UniqueName: "sum",
Typ: &types.Function{
Input: []types.Type{types.Int, types.Int},
Output: []types.Type{types.Int},
},
})
one := fn.AppendInt(1)
two := fn.AppendInt(2)
call := fn.Append(&ssa.Call{Arguments: ssa.Arguments{sum, one, two}})
assert.Equal(t, call.String(), "sum(1, 2)")
assert.True(t, call.Type() == types.Int)
}

View file

@ -2,6 +2,7 @@ package ssa
import (
"fmt"
"strings"
"git.urbach.dev/cli/q/src/types"
)
@ -39,7 +40,17 @@ func (v *Return) IsConst() bool {
}
func (v *Return) String() string {
return fmt.Sprintf("return %v", v.Arguments)
if len(v.Arguments) == 0 {
return "return"
}
args := make([]string, 0, len(v.Arguments))
for _, arg := range v.Arguments {
args = append(args, arg.String())
}
return fmt.Sprintf("return %s", strings.Join(args, ", "))
}
func (v *Return) Type() types.Type {

30
src/ssa/Return_test.go Normal file
View file

@ -0,0 +1,30 @@
package ssa_test
import (
"testing"
"git.urbach.dev/cli/q/src/ssa"
"git.urbach.dev/cli/q/src/types"
"git.urbach.dev/go/assert"
)
func TestReturn(t *testing.T) {
fn := ssa.IR{}
ret := fn.Append(&ssa.Return{})
one := fn.AppendInt(1)
ret2 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{one}})
two := fn.AppendInt(2)
ret3 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{one, two}})
ret4 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{two, one}})
ret5 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{one, two}})
assert.True(t, ret.Type() == types.Void)
assert.Equal(t, ret.String(), "return")
assert.Equal(t, ret2.String(), "return 1")
assert.Equal(t, ret3.String(), "return 1, 2")
assert.Equal(t, ret4.String(), "return 2, 1")
assert.False(t, ret5.Equals(one))
assert.False(t, ret5.Equals(ret))
assert.False(t, ret5.Equals(ret4))
assert.True(t, ret5.Equals(ret3))
}

View file

@ -2,6 +2,7 @@ package ssa
import (
"fmt"
"strings"
"git.urbach.dev/cli/q/src/types"
)
@ -27,7 +28,13 @@ func (v *Syscall) IsConst() bool {
}
func (v *Syscall) String() string {
return fmt.Sprintf("syscall(%v)", v.Arguments)
args := make([]string, 0, len(v.Arguments))
for _, arg := range v.Arguments {
args = append(args, arg.String())
}
return fmt.Sprintf("syscall(%s)", strings.Join(args, ", "))
}
func (v *Syscall) Type() types.Type {

27
src/ssa/Syscall_test.go Normal file
View file

@ -0,0 +1,27 @@
package ssa_test
import (
"testing"
"git.urbach.dev/cli/q/src/ssa"
"git.urbach.dev/cli/q/src/types"
"git.urbach.dev/go/assert"
)
func TestSyscall(t *testing.T) {
fn := ssa.IR{}
syscall := fn.Append(&ssa.Syscall{})
one := fn.AppendInt(1)
syscall2 := fn.Append(&ssa.Syscall{Arguments: ssa.Arguments{one}})
two := fn.AppendInt(2)
syscall3 := fn.Append(&ssa.Syscall{Arguments: ssa.Arguments{one, two}})
syscall4 := fn.Append(&ssa.Syscall{Arguments: ssa.Arguments{one, two}})
assert.True(t, syscall.Type() == types.Any)
assert.Equal(t, syscall.String(), "syscall()")
assert.Equal(t, syscall2.String(), "syscall(1)")
assert.Equal(t, syscall3.String(), "syscall(1, 2)")
assert.False(t, syscall4.Equals(one))
assert.False(t, syscall4.Equals(syscall))
assert.True(t, syscall4.Equals(syscall3))
}

View file

@ -1,22 +0,0 @@
package ssa_test
import (
"testing"
"git.urbach.dev/cli/q/src/ssa"
"git.urbach.dev/cli/q/src/token"
"git.urbach.dev/go/assert"
)
func TestFunction(t *testing.T) {
fn := ssa.IR{}
a := fn.AppendInt(1)
b := fn.AppendInt(2)
c := fn.Append(&ssa.BinaryOperation{Op: token.Add, Left: a, Right: b})
fn.AddBlock()
d := fn.AppendInt(3)
e := fn.AppendInt(4)
f := fn.Append(&ssa.BinaryOperation{Op: token.Add, Left: d, Right: e})
assert.Equal(t, c.String(), "1 + 2")
assert.Equal(t, f.String(), "3 + 4")
}