This commit is contained in:
parent
72ace483e4
commit
0eaeb726b9
8 changed files with 112 additions and 101 deletions
|
@ -27,8 +27,14 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Dependencies.Add(function)
|
f.Dependencies.Add(function)
|
||||||
v := f.AppendFunction(function.UniqueName, function.Type, function.IsExtern())
|
|
||||||
v.SetSource(expr.Source)
|
v := f.Append(&ssa.Function{
|
||||||
|
UniqueName: function.UniqueName,
|
||||||
|
Typ: function.Type,
|
||||||
|
IsExtern: function.IsExtern(),
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
|
})
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,26 +47,33 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
v := f.AppendInt(number)
|
v := f.Append(&ssa.Int{
|
||||||
v.SetSource(expr.Source)
|
Int: number,
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
|
})
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
|
|
||||||
case token.String:
|
case token.String:
|
||||||
data := expr.Token.Bytes(f.File.Bytes)
|
data := expr.Token.Bytes(f.File.Bytes)
|
||||||
data = Unescape(data)
|
data = Unescape(data)
|
||||||
|
|
||||||
length := f.AppendInt(len(data))
|
length := f.Append(&ssa.Int{
|
||||||
length.SetSource(expr.Source)
|
Int: len(data),
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
|
})
|
||||||
|
|
||||||
pointer := f.AppendBytes(data)
|
pointer := f.Append(&ssa.Bytes{
|
||||||
pointer.SetSource(expr.Source)
|
Bytes: data,
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
|
})
|
||||||
|
|
||||||
v := f.Append(&ssa.Struct{
|
v := f.Append(&ssa.Struct{
|
||||||
Arguments: []ssa.Value{pointer, length},
|
Arguments: []ssa.Value{pointer, length},
|
||||||
Typ: types.String,
|
Typ: types.String,
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
})
|
})
|
||||||
|
|
||||||
v.SetSource(expr.Source)
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,17 +88,6 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
if children[0].Token.Kind == token.Identifier {
|
if children[0].Token.Kind == token.Identifier {
|
||||||
funcName := children[0].String(f.File.Bytes)
|
funcName := children[0].String(f.File.Bytes)
|
||||||
|
|
||||||
if funcName == "len" {
|
|
||||||
identifier := children[1].String(f.File.Bytes)
|
|
||||||
length, exists := f.Identifiers[identifier+".len"]
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
return nil, errors.New(&UnknownIdentifier{Name: identifier + ".len"}, f.File, expr.Token.Position)
|
|
||||||
}
|
|
||||||
|
|
||||||
return length, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if funcName == "syscall" {
|
if funcName == "syscall" {
|
||||||
children = children[1:]
|
children = children[1:]
|
||||||
isSyscall = true
|
isSyscall = true
|
||||||
|
@ -111,47 +113,57 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.Append(syscall), nil
|
return f.Append(syscall), nil
|
||||||
} else {
|
}
|
||||||
name := args[0].(*ssa.Function).UniqueName
|
|
||||||
fn := f.All.Functions[name]
|
|
||||||
parameters := args[1:]
|
|
||||||
|
|
||||||
if len(parameters) != len(fn.Input) {
|
name := args[0].(*ssa.Function).UniqueName
|
||||||
return nil, errors.New(&ParameterCountMismatch{Function: name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, expr.Source[0].Position)
|
fn := f.All.Functions[name]
|
||||||
}
|
parameters := args[1:]
|
||||||
|
|
||||||
for i, param := range slices.Backward(parameters) {
|
if len(parameters) != len(fn.Input) {
|
||||||
if !types.Is(param.Type(), fn.Input[i].Typ) {
|
return nil, errors.New(&ParameterCountMismatch{Function: name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, expr.Source[0].Position)
|
||||||
_, isPointer := fn.Input[i].Typ.(*types.Pointer)
|
}
|
||||||
|
|
||||||
if isPointer {
|
for i, param := range slices.Backward(parameters) {
|
||||||
number, isInt := param.(*ssa.Int)
|
if !types.Is(param.Type(), fn.Input[i].Typ) {
|
||||||
|
_, isPointer := fn.Input[i].Typ.(*types.Pointer)
|
||||||
|
|
||||||
if isInt && number.Int == 0 {
|
if isPointer {
|
||||||
continue
|
number, isInt := param.(*ssa.Int)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary hack to allow int64 -> uint32 conversion
|
if isInt && number.Int == 0 {
|
||||||
if types.Is(param.Type(), types.AnyInt) && types.Is(fn.Input[i].Typ, types.AnyInt) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New(&TypeMismatch{
|
|
||||||
Encountered: param.Type().Name(),
|
|
||||||
Expected: fn.Input[i].Typ.Name(),
|
|
||||||
ParameterName: fn.Input[i].Name,
|
|
||||||
}, f.File, param.Start())
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if fn.IsExtern() {
|
// Temporary hack to allow int64 -> uint32 conversion
|
||||||
return f.Append(&ssa.CallExtern{Arguments: args, Source: ssa.Source(expr.Source)}), nil
|
if types.Is(param.Type(), types.AnyInt) && types.Is(fn.Input[i].Typ, types.AnyInt) {
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
return f.Append(&ssa.Call{Arguments: args, Source: ssa.Source(expr.Source)}), nil
|
return nil, errors.New(&TypeMismatch{
|
||||||
|
Encountered: param.Type().Name(),
|
||||||
|
Expected: fn.Input[i].Typ.Name(),
|
||||||
|
ParameterName: fn.Input[i].Name,
|
||||||
|
}, f.File, param.Start())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fn.IsExtern() {
|
||||||
|
v := f.Append(&ssa.CallExtern{
|
||||||
|
Arguments: args,
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
|
})
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v := f.Append(&ssa.Call{
|
||||||
|
Arguments: args,
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
|
})
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
|
||||||
case token.Dot:
|
case token.Dot:
|
||||||
left := expr.Children[0]
|
left := expr.Children[0]
|
||||||
right := expr.Children[1]
|
right := expr.Children[1]
|
||||||
|
@ -167,8 +179,12 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
return nil, errors.New(&UnknownStructField{StructName: structure.Name(), FieldName: rightText}, f.File, right.Token.Position)
|
return nil, errors.New(&UnknownStructField{StructName: structure.Name(), FieldName: rightText}, f.File, right.Token.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := f.Append(&ssa.StructField{Struct: identifier, Field: field})
|
v := f.Append(&ssa.StructField{
|
||||||
v.SetSource(expr.Source)
|
Struct: identifier,
|
||||||
|
Field: field,
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
|
})
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,13 +198,19 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
f.Dependencies.Add(function)
|
f.Dependencies.Add(function)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := f.AppendFunction(function.UniqueName, function.Type, function.IsExtern())
|
v := f.Append(&ssa.Function{
|
||||||
v.SetSource(expr.Source)
|
UniqueName: function.UniqueName,
|
||||||
|
Typ: function.Type,
|
||||||
|
IsExtern: function.IsExtern(),
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
|
})
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New(&UnknownIdentifier{Name: label}, f.File, left.Token.Position)
|
return nil, errors.New(&UnknownIdentifier{Name: label}, f.File, left.Token.Position)
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
default:
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -11,12 +11,12 @@ import (
|
||||||
|
|
||||||
func TestBinaryOp(t *testing.T) {
|
func TestBinaryOp(t *testing.T) {
|
||||||
fn := ssa.IR{}
|
fn := ssa.IR{}
|
||||||
a := fn.AppendInt(1)
|
a := fn.Append(&ssa.Int{Int: 1})
|
||||||
b := fn.AppendInt(2)
|
b := fn.Append(&ssa.Int{Int: 2})
|
||||||
c := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: a, Right: b})
|
c := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: a, Right: b})
|
||||||
fn.AddBlock()
|
fn.AddBlock()
|
||||||
d := fn.AppendInt(3)
|
d := fn.Append(&ssa.Int{Int: 3})
|
||||||
e := fn.AppendInt(4)
|
e := fn.Append(&ssa.Int{Int: 4})
|
||||||
f := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: d, Right: e})
|
f := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: d, Right: e})
|
||||||
|
|
||||||
assert.Equal(t, c.String(), "1 + 2")
|
assert.Equal(t, c.String(), "1 + 2")
|
||||||
|
@ -26,11 +26,11 @@ func TestBinaryOp(t *testing.T) {
|
||||||
|
|
||||||
func TestBinaryOpEquals(t *testing.T) {
|
func TestBinaryOpEquals(t *testing.T) {
|
||||||
fn := ssa.IR{}
|
fn := ssa.IR{}
|
||||||
one := fn.AppendInt(1)
|
one := fn.Append(&ssa.Int{Int: 1})
|
||||||
two := fn.AppendInt(2)
|
two := fn.Append(&ssa.Int{Int: 2})
|
||||||
binOp := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: one, Right: two})
|
binOp := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: one, Right: two})
|
||||||
oneDup := fn.AppendInt(1)
|
oneDup := fn.Append(&ssa.Int{Int: 1})
|
||||||
twoDup := fn.AppendInt(2)
|
twoDup := fn.Append(&ssa.Int{Int: 2})
|
||||||
binOpDup := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: oneDup, Right: twoDup})
|
binOpDup := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: oneDup, Right: twoDup})
|
||||||
binOpDiff := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: oneDup, Right: oneDup})
|
binOpDiff := fn.Append(&ssa.BinaryOp{Op: token.Add, Left: oneDup, Right: oneDup})
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ func TestBytes(t *testing.T) {
|
||||||
hello := fn.Append(&ssa.Bytes{Bytes: []byte("Hello")})
|
hello := fn.Append(&ssa.Bytes{Bytes: []byte("Hello")})
|
||||||
world := fn.Append(&ssa.Bytes{Bytes: []byte("World")})
|
world := fn.Append(&ssa.Bytes{Bytes: []byte("World")})
|
||||||
helloDup := fn.Append(&ssa.Bytes{Bytes: []byte("Hello")})
|
helloDup := fn.Append(&ssa.Bytes{Bytes: []byte("Hello")})
|
||||||
one := fn.AppendInt(1)
|
one := fn.Append(&ssa.Int{Int: 1})
|
||||||
|
|
||||||
assert.False(t, hello.Equals(world))
|
assert.False(t, hello.Equals(world))
|
||||||
assert.False(t, hello.Equals(one))
|
assert.False(t, hello.Equals(one))
|
||||||
|
|
|
@ -12,7 +12,7 @@ func TestCall(t *testing.T) {
|
||||||
fn := ssa.IR{}
|
fn := ssa.IR{}
|
||||||
myfunc := fn.Append(&ssa.Function{UniqueName: "myfunc", Typ: &types.Function{}})
|
myfunc := fn.Append(&ssa.Function{UniqueName: "myfunc", Typ: &types.Function{}})
|
||||||
call := fn.Append(&ssa.Call{Arguments: ssa.Arguments{myfunc}})
|
call := fn.Append(&ssa.Call{Arguments: ssa.Arguments{myfunc}})
|
||||||
one := fn.AppendInt(1)
|
one := fn.Append(&ssa.Int{Int: 1})
|
||||||
call2 := fn.Append(&ssa.Call{Arguments: ssa.Arguments{myfunc, one}})
|
call2 := fn.Append(&ssa.Call{Arguments: ssa.Arguments{myfunc, one}})
|
||||||
|
|
||||||
assert.True(t, call.Type() == types.Void)
|
assert.True(t, call.Type() == types.Void)
|
||||||
|
@ -31,8 +31,8 @@ func TestCallEquals(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
one := fn.AppendInt(1)
|
one := fn.Append(&ssa.Int{Int: 1})
|
||||||
two := fn.AppendInt(2)
|
two := fn.Append(&ssa.Int{Int: 2})
|
||||||
call1 := fn.Append(&ssa.Call{Arguments: ssa.Arguments{sum, one, two}})
|
call1 := fn.Append(&ssa.Call{Arguments: ssa.Arguments{sum, one, two}})
|
||||||
call2 := fn.Append(&ssa.Call{Arguments: ssa.Arguments{sum, one, two}})
|
call2 := fn.Append(&ssa.Call{Arguments: ssa.Arguments{sum, one, two}})
|
||||||
|
|
||||||
|
@ -51,8 +51,8 @@ func TestCallReturnType(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
one := fn.AppendInt(1)
|
one := fn.Append(&ssa.Int{Int: 1})
|
||||||
two := fn.AppendInt(2)
|
two := fn.Append(&ssa.Int{Int: 2})
|
||||||
call := fn.Append(&ssa.Call{Arguments: ssa.Arguments{sum, one, two}})
|
call := fn.Append(&ssa.Call{Arguments: ssa.Arguments{sum, one, two}})
|
||||||
|
|
||||||
assert.Equal(t, call.String(), "sum(1, 2)")
|
assert.Equal(t, call.String(), "sum(1, 2)")
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IR is a list of basic blocks.
|
// IR is a list of basic blocks.
|
||||||
type IR struct {
|
type IR struct {
|
||||||
Blocks []*Block
|
Blocks []*Block
|
||||||
|
@ -26,12 +22,10 @@ func (f *IR) Append(instr Value) Value {
|
||||||
f.AddBlock()
|
f.AddBlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
if instr.IsConst() {
|
existing := f.FindExisting(instr)
|
||||||
for existing := range f.Values {
|
|
||||||
if existing.IsConst() && instr.Equals(existing) {
|
if existing != nil {
|
||||||
return existing
|
return existing
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
instr.SetID(f.nextId)
|
instr.SetID(f.nextId)
|
||||||
|
@ -39,24 +33,19 @@ func (f *IR) Append(instr Value) Value {
|
||||||
return f.Blocks[len(f.Blocks)-1].Append(instr)
|
return f.Blocks[len(f.Blocks)-1].Append(instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendInt adds a new integer value to the last block.
|
// FindExisting returns an equal instruction that's already appended or `nil` if none could be found.
|
||||||
func (f *IR) AppendInt(x int) Value {
|
func (f *IR) FindExisting(instr Value) Value {
|
||||||
return f.Append(&Int{Int: x})
|
if !instr.IsConst() {
|
||||||
}
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AppendFunction adds a new function value to the last block.
|
for existing := range f.Values {
|
||||||
func (f *IR) AppendFunction(name string, typ *types.Function, extern bool) Value {
|
if existing.IsConst() && instr.Equals(existing) {
|
||||||
return f.Append(&Function{UniqueName: name, Typ: typ, IsExtern: extern})
|
return existing
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AppendBytes adds a new byte slice value to the last block.
|
return nil
|
||||||
func (f *IR) AppendBytes(s []byte) Value {
|
|
||||||
return f.Append(&Bytes{Bytes: s})
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendString adds a new string value to the last block.
|
|
||||||
func (f *IR) AppendString(s string) Value {
|
|
||||||
return f.Append(&Bytes{Bytes: []byte(s)})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values yields on each value.
|
// Values yields on each value.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"strconv"
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
@ -36,7 +36,7 @@ func (v *Int) Debug(expand bool) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Int) String() string {
|
func (v *Int) String() string {
|
||||||
return fmt.Sprintf("%d", v.Int)
|
return strconv.Itoa(v.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Int) Type() types.Type {
|
func (v *Int) Type() types.Type {
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
func TestReturn(t *testing.T) {
|
func TestReturn(t *testing.T) {
|
||||||
fn := ssa.IR{}
|
fn := ssa.IR{}
|
||||||
ret := fn.Append(&ssa.Return{})
|
ret := fn.Append(&ssa.Return{})
|
||||||
one := fn.AppendInt(1)
|
one := fn.Append(&ssa.Int{Int: 1})
|
||||||
ret2 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{one}})
|
ret2 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{one}})
|
||||||
two := fn.AppendInt(2)
|
two := fn.Append(&ssa.Int{Int: 2})
|
||||||
ret3 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{one, two}})
|
ret3 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{one, two}})
|
||||||
ret4 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{two, one}})
|
ret4 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{two, one}})
|
||||||
ret5 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{one, two}})
|
ret5 := fn.Append(&ssa.Return{Arguments: ssa.Arguments{one, two}})
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
func TestSyscall(t *testing.T) {
|
func TestSyscall(t *testing.T) {
|
||||||
fn := ssa.IR{}
|
fn := ssa.IR{}
|
||||||
syscall := fn.Append(&ssa.Syscall{})
|
syscall := fn.Append(&ssa.Syscall{})
|
||||||
one := fn.AppendInt(1)
|
one := fn.Append(&ssa.Int{Int: 1})
|
||||||
syscall2 := fn.Append(&ssa.Syscall{Arguments: ssa.Arguments{one}})
|
syscall2 := fn.Append(&ssa.Syscall{Arguments: ssa.Arguments{one}})
|
||||||
two := fn.AppendInt(2)
|
two := fn.Append(&ssa.Int{Int: 2})
|
||||||
syscall3 := fn.Append(&ssa.Syscall{Arguments: ssa.Arguments{one, two}})
|
syscall3 := fn.Append(&ssa.Syscall{Arguments: ssa.Arguments{one, two}})
|
||||||
syscall4 := fn.Append(&ssa.Syscall{Arguments: ssa.Arguments{one, two}})
|
syscall4 := fn.Append(&ssa.Syscall{Arguments: ssa.Arguments{one, two}})
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue