This commit is contained in:
parent
643f17af8e
commit
a1f6c66736
11 changed files with 221 additions and 33 deletions
|
@ -36,7 +36,7 @@ func NewFunction(name string, file *fs.File) *Function {
|
||||||
Name: name,
|
Name: name,
|
||||||
File: file,
|
File: file,
|
||||||
UniqueName: fmt.Sprintf("%s.%s", file.Package, name),
|
UniqueName: fmt.Sprintf("%s.%s", file.Package, name),
|
||||||
Identifiers: make(map[string]ssa.Value),
|
Identifiers: make(map[string]ssa.Value, 8),
|
||||||
IR: ssa.IR{
|
IR: ssa.IR{
|
||||||
Blocks: []*ssa.Block{
|
Blocks: []*ssa.Block{
|
||||||
{Instructions: make([]ssa.Value, 0, 8)},
|
{Instructions: make([]ssa.Value, 0, 8)},
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BinaryOperation struct {
|
type BinaryOp struct {
|
||||||
Left Value
|
Left Value
|
||||||
Right Value
|
Right Value
|
||||||
Op token.Kind
|
Op token.Kind
|
||||||
|
@ -16,12 +16,12 @@ type BinaryOperation struct {
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *BinaryOperation) Dependencies() []Value {
|
func (v *BinaryOp) Dependencies() []Value {
|
||||||
return []Value{v.Left, v.Right}
|
return []Value{v.Left, v.Right}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *BinaryOperation) Equals(v Value) bool {
|
func (a *BinaryOp) Equals(v Value) bool {
|
||||||
b, sameType := v.(*BinaryOperation)
|
b, sameType := v.(*BinaryOp)
|
||||||
|
|
||||||
if !sameType {
|
if !sameType {
|
||||||
return false
|
return false
|
||||||
|
@ -38,14 +38,14 @@ func (a *BinaryOperation) Equals(v Value) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *BinaryOperation) IsConst() bool {
|
func (v *BinaryOp) IsConst() bool {
|
||||||
return true
|
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)
|
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()
|
return v.Left.Type()
|
||||||
}
|
}
|
45
src/ssa/BinaryOp_test.go
Normal file
45
src/ssa/BinaryOp_test.go
Normal 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
23
src/ssa/Bytes_test.go
Normal 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))
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
@ -27,7 +28,13 @@ func (v *Call) IsConst() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Call) String() string {
|
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 {
|
func (v *Call) Type() types.Type {
|
||||||
|
|
60
src/ssa/Call_test.go
Normal file
60
src/ssa/Call_test.go
Normal 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)
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
@ -39,7 +40,17 @@ func (v *Return) IsConst() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Return) String() string {
|
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 {
|
func (v *Return) Type() types.Type {
|
||||||
|
|
30
src/ssa/Return_test.go
Normal file
30
src/ssa/Return_test.go
Normal 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))
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
@ -27,7 +28,13 @@ func (v *Syscall) IsConst() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Syscall) String() string {
|
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 {
|
func (v *Syscall) Type() types.Type {
|
||||||
|
|
27
src/ssa/Syscall_test.go
Normal file
27
src/ssa/Syscall_test.go
Normal 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))
|
||||||
|
}
|
|
@ -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")
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue