Implemented lazy appending of struct fields
All checks were successful
/ test (push) Successful in 16s
All checks were successful
/ test (push) Successful in 16s
This commit is contained in:
parent
c5588510e2
commit
7cc371070a
11 changed files with 136 additions and 55 deletions
11
examples/winapi/winapi.q
Normal file
11
examples/winapi/winapi.q
Normal file
|
@ -0,0 +1,11 @@
|
|||
main() {
|
||||
title := "Title\0"
|
||||
message := "Message\0"
|
||||
user32.MessageBoxA(0, message.ptr, title.ptr, 0x240040)
|
||||
}
|
||||
|
||||
extern {
|
||||
user32 {
|
||||
MessageBoxA(window *any, text *byte, title *byte, flags uint) -> (button int)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package codegen
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
"git.urbach.dev/cli/q/src/cpu"
|
||||
"git.urbach.dev/cli/q/src/ssa"
|
||||
|
@ -86,7 +88,7 @@ func (f *Function) exec(step *step) {
|
|||
args := instr.Arguments
|
||||
var pushed []cpu.Register
|
||||
|
||||
for i, arg := range args {
|
||||
for i, arg := range slices.Backward(args) {
|
||||
if i >= len(f.CPU.ExternCall.In) {
|
||||
pushed = append(pushed, f.ValueToStep[arg].Register)
|
||||
continue
|
||||
|
@ -122,6 +124,10 @@ func (f *Function) exec(step *step) {
|
|||
})
|
||||
|
||||
case *ssa.Int:
|
||||
if step.Register == -1 {
|
||||
return
|
||||
}
|
||||
|
||||
f.Assembler.Append(&asm.MoveRegisterNumber{
|
||||
Destination: step.Register,
|
||||
Number: instr.Int,
|
||||
|
|
|
@ -17,7 +17,7 @@ func (f *Function) checkDeadCode() error {
|
|||
}
|
||||
|
||||
source := instr.(ssa.HasSource)
|
||||
return errors.New(&UnusedValue{Value: string(f.File.Bytes[source.Start():source.End()])}, f.File, source.Start())
|
||||
return errors.New(&UnusedValue{Value: instr.String()}, f.File, source.Start())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
15
src/core/compileDefinition.go
Normal file
15
src/core/compileDefinition.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/expression"
|
||||
)
|
||||
|
||||
// compileDefinition compiles a define instruction.
|
||||
func (f *Function) compileDefinition(expr *expression.Expression) error {
|
||||
left := expr.Children[0]
|
||||
right := expr.Children[1]
|
||||
name := left.String(f.File.Bytes)
|
||||
value, err := f.eval(right)
|
||||
f.Identifiers[name] = value
|
||||
return err
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/errors"
|
||||
"git.urbach.dev/cli/q/src/expression"
|
||||
"git.urbach.dev/cli/q/src/token"
|
||||
)
|
||||
|
@ -16,13 +17,11 @@ func (f *Function) compileInstruction(instr token.List) error {
|
|||
|
||||
expr := expression.Parse(instr)
|
||||
|
||||
if expr.Token.Kind == token.Define {
|
||||
left := expr.Children[0]
|
||||
right := expr.Children[1]
|
||||
name := left.String(f.File.Bytes)
|
||||
value, err := f.eval(right)
|
||||
f.Identifiers[name] = value
|
||||
return err
|
||||
switch expr.Token.Kind {
|
||||
case token.Define:
|
||||
return f.compileDefinition(expr)
|
||||
case token.String:
|
||||
return errors.New(&UnusedValue{Value: expr.String(f.File.Bytes)}, f.File, expr.Token.Position)
|
||||
}
|
||||
|
||||
_, err := f.eval(expr)
|
||||
|
|
|
@ -30,7 +30,7 @@ func (f *Function) decompose(nodes []*expression.Expression, typeCheck []*ssa.Pa
|
|||
|
||||
if isStruct {
|
||||
for _, field := range structure.Arguments {
|
||||
args = append(args, field)
|
||||
args = append(args, f.Append(field))
|
||||
}
|
||||
|
||||
continue
|
||||
|
|
|
@ -30,7 +30,8 @@ var errs = []struct {
|
|||
{"UnknownIdentifier5.q", &core.UnknownIdentifier{Name: "unknown"}},
|
||||
{"UnknownIdentifier6.q", &core.UnknownIdentifier{Name: "os"}},
|
||||
{"UnknownIdentifier7.q", &core.UnknownIdentifier{Name: "os.unknown"}},
|
||||
{"UnusedValue.q", &core.UnusedValue{Value: "2+3"}},
|
||||
{"UnusedValue.q", &core.UnusedValue{Value: "2 + 3"}},
|
||||
{"UnusedValue2.q", &core.UnusedValue{Value: "\"not used\""}},
|
||||
}
|
||||
|
||||
func TestErrors(t *testing.T) {
|
||||
|
|
102
src/core/eval.go
102
src/core/eval.go
|
@ -18,13 +18,19 @@ func (f *Function) eval(expr *expression.Expression) (ssa.Value, error) {
|
|||
name := expr.Token.String(f.File.Bytes)
|
||||
value, exists := f.Identifiers[name]
|
||||
|
||||
if !exists {
|
||||
function := f.All.Function(f.File.Package, name)
|
||||
if exists {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
if function == nil {
|
||||
return nil, errors.New(&UnknownIdentifier{Name: name}, f.File, expr.Token.Position)
|
||||
}
|
||||
_, exists = f.All.Packages[name]
|
||||
|
||||
if exists {
|
||||
return &ssa.Package{Name: name}, nil
|
||||
}
|
||||
|
||||
function := f.All.Function(f.File.Package, name)
|
||||
|
||||
if function != nil {
|
||||
f.Dependencies.Add(function)
|
||||
|
||||
v := &ssa.Function{
|
||||
|
@ -38,7 +44,7 @@ func (f *Function) eval(expr *expression.Expression) (ssa.Value, error) {
|
|||
return v, nil
|
||||
}
|
||||
|
||||
return value, nil
|
||||
return nil, errors.New(&UnknownIdentifier{Name: name}, f.File, expr.Token.Position)
|
||||
|
||||
case token.Number:
|
||||
number, err := f.toNumber(expr.Token)
|
||||
|
@ -58,15 +64,15 @@ func (f *Function) eval(expr *expression.Expression) (ssa.Value, error) {
|
|||
data := expr.Token.Bytes(f.File.Bytes)
|
||||
data = unescape(data)
|
||||
|
||||
length := f.Append(&ssa.Int{
|
||||
length := &ssa.Int{
|
||||
Int: len(data),
|
||||
Source: ssa.Source(expr.Source),
|
||||
})
|
||||
}
|
||||
|
||||
pointer := f.Append(&ssa.Bytes{
|
||||
pointer := &ssa.Bytes{
|
||||
Bytes: data,
|
||||
Source: ssa.Source(expr.Source),
|
||||
})
|
||||
}
|
||||
|
||||
v := &ssa.Struct{
|
||||
Arguments: []ssa.Value{pointer, length},
|
||||
|
@ -141,49 +147,59 @@ func (f *Function) eval(expr *expression.Expression) (ssa.Value, error) {
|
|||
right := expr.Children[1]
|
||||
leftText := left.String(f.File.Bytes)
|
||||
rightText := right.String(f.File.Bytes)
|
||||
fullName := fmt.Sprintf("%s.%s", leftText, rightText)
|
||||
identifier, exists := f.Identifiers[fullName]
|
||||
leftValue, err := f.eval(left)
|
||||
|
||||
if exists {
|
||||
return identifier, nil
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkg, exists := f.All.Packages[leftText]
|
||||
switch leftValue := leftValue.(type) {
|
||||
case *ssa.Package:
|
||||
pkg := f.All.Packages[leftText]
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New(&UnknownIdentifier{Name: leftText}, f.File, left.Token.Position)
|
||||
}
|
||||
if !pkg.IsExtern && f != f.All.Init {
|
||||
_, exists := f.File.Imports[leftText]
|
||||
|
||||
if !pkg.IsExtern && f != f.All.Init {
|
||||
_, exists = f.File.Imports[leftText]
|
||||
if !exists {
|
||||
return nil, errors.New(&UnknownIdentifier{Name: leftText}, f.File, left.Token.Position)
|
||||
}
|
||||
}
|
||||
|
||||
function, exists := pkg.Functions[rightText]
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New(&UnknownIdentifier{Name: leftText}, f.File, left.Token.Position)
|
||||
return nil, errors.New(&UnknownIdentifier{Name: fmt.Sprintf("%s.%s", pkg.Name, rightText)}, f.File, left.Token.Position)
|
||||
}
|
||||
|
||||
if function.IsExtern() {
|
||||
f.Assembler.Libraries.Append(function.Package, function.Name)
|
||||
} else {
|
||||
f.Dependencies.Add(function)
|
||||
}
|
||||
|
||||
v := &ssa.Function{
|
||||
Package: function.Package,
|
||||
Name: function.Name,
|
||||
Typ: function.Type,
|
||||
IsExtern: function.IsExtern(),
|
||||
Source: ssa.Source(expr.Source),
|
||||
}
|
||||
|
||||
return v, nil
|
||||
|
||||
case *ssa.Struct:
|
||||
field := leftValue.Typ.FieldByName(rightText)
|
||||
|
||||
if field == nil {
|
||||
panic("unknown field")
|
||||
}
|
||||
|
||||
return f.Append(leftValue.Arguments[field.Index]), nil
|
||||
|
||||
default:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
function, exists := pkg.Functions[rightText]
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New(&UnknownIdentifier{Name: fullName}, f.File, left.Token.Position)
|
||||
}
|
||||
|
||||
if function.IsExtern() {
|
||||
f.Assembler.Libraries.Append(function.Package, function.Name)
|
||||
} else {
|
||||
f.Dependencies.Add(function)
|
||||
}
|
||||
|
||||
v := &ssa.Function{
|
||||
Package: function.Package,
|
||||
Name: function.Name,
|
||||
Typ: function.Type,
|
||||
IsExtern: function.IsExtern(),
|
||||
Source: ssa.Source(expr.Source),
|
||||
}
|
||||
|
||||
return v, nil
|
||||
|
||||
default:
|
||||
if expr.Token.IsOperator() {
|
||||
left := expr.Children[0]
|
||||
|
|
|
@ -19,6 +19,8 @@ func (f *Function) registerInputs() {
|
|||
structType, isStructType := input.Typ.(*types.Struct)
|
||||
|
||||
if isStructType {
|
||||
structure := &ssa.Struct{Typ: structType}
|
||||
|
||||
for _, field := range structType.Fields {
|
||||
param := &ssa.Parameter{
|
||||
Index: uint8(offset + i),
|
||||
|
@ -27,12 +29,13 @@ func (f *Function) registerInputs() {
|
|||
Source: input.Source,
|
||||
}
|
||||
|
||||
f.Identifiers[param.Name] = param
|
||||
f.Append(param)
|
||||
structure.Arguments = append(structure.Arguments, param)
|
||||
offset++
|
||||
}
|
||||
|
||||
offset--
|
||||
f.Identifiers[input.Name] = structure
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
3
src/core/testdata/UnusedValue2.q
vendored
Normal file
3
src/core/testdata/UnusedValue2.q
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
main() {
|
||||
"not used"
|
||||
}
|
27
src/ssa/Package.go
Normal file
27
src/ssa/Package.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package ssa
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
type Package struct {
|
||||
Name string
|
||||
IsExtern bool
|
||||
}
|
||||
|
||||
func (v *Package) AddUser(Value) { panic("package can not be used as a dependency") }
|
||||
func (v *Package) Inputs() []Value { return nil }
|
||||
func (v *Package) IsConst() bool { return true }
|
||||
func (v *Package) String() string { return v.Name }
|
||||
func (v *Package) Type() types.Type { return nil }
|
||||
func (v *Package) Users() []Value { return nil }
|
||||
|
||||
func (a *Package) Equals(v Value) bool {
|
||||
b, sameType := v.(*Package)
|
||||
|
||||
if !sameType {
|
||||
return false
|
||||
}
|
||||
|
||||
return a.Name == b.Name
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue