This commit is contained in:
parent
643f17af8e
commit
1fa27dca51
11 changed files with 221 additions and 33 deletions
|
@ -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)},
|
||||
|
|
|
@ -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
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 (
|
||||
"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
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 (
|
||||
"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
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 (
|
||||
"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
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