Implemented package specific structs
This commit is contained in:
parent
91bafc0867
commit
97cdcbd1cb
@ -3,13 +3,6 @@
|
|||||||
// [2] curl http://127.0.0.1:8080
|
// [2] curl http://127.0.0.1:8080
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
struct sockaddr_in {
|
|
||||||
sin_family Int16
|
|
||||||
sin_port Int16
|
|
||||||
sin_addr Int64
|
|
||||||
sin_zero Int64
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
socket := sys.socket(2, 1, 0)
|
socket := sys.socket(2, 1, 0)
|
||||||
|
|
||||||
@ -18,7 +11,7 @@ main() {
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := new(sockaddr_in)
|
addr := new(sys.sockaddr_in)
|
||||||
addr.sin_family = 2
|
addr.sin_family = 2
|
||||||
addr.sin_port = 0x901F
|
addr.sin_port = 0x901F
|
||||||
addr.sin_addr = 0
|
addr.sin_addr = 0
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
struct sockaddr_in {
|
||||||
|
sin_family Int16
|
||||||
|
sin_port Int16
|
||||||
|
sin_addr Int64
|
||||||
|
sin_zero Int64
|
||||||
|
}
|
||||||
|
|
||||||
socket(family Int, type Int, protocol Int) -> Int {
|
socket(family Int, type Int, protocol Int) -> Int {
|
||||||
return syscall(41, family, type, protocol)
|
return syscall(41, family, type, protocol)
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ func New(files ...string) *Build {
|
|||||||
|
|
||||||
// Run compiles the input files.
|
// Run compiles the input files.
|
||||||
func (build *Build) Run() (compiler.Result, error) {
|
func (build *Build) Run() (compiler.Result, error) {
|
||||||
files, functions, types, errors := scanner.Scan(build.Files)
|
files, functions, structs, errors := scanner.Scan(build.Files)
|
||||||
return compiler.Compile(files, functions, types, errors)
|
return compiler.Compile(files, functions, structs, errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executable returns the path to the executable.
|
// Executable returns the path to the executable.
|
||||||
|
@ -10,22 +10,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Compile waits for the scan to finish and compiles all functions.
|
// Compile waits for the scan to finish and compiles all functions.
|
||||||
func Compile(files <-chan *fs.File, functions <-chan *core.Function, structs <-chan types.Type, errs <-chan error) (Result, error) {
|
func Compile(files <-chan *fs.File, functions <-chan *core.Function, structs <-chan *types.Struct, errs <-chan error) (Result, error) {
|
||||||
result := Result{}
|
result := Result{}
|
||||||
allFiles := make([]*fs.File, 0, 8)
|
allFiles := make([]*fs.File, 0, 8)
|
||||||
allFunctions := map[string]*core.Function{}
|
allFunctions := map[string]*core.Function{}
|
||||||
|
allStructs := map[string]*types.Struct{}
|
||||||
allTypes := map[string]types.Type{
|
|
||||||
"Int": types.Int,
|
|
||||||
"Int64": types.Int64,
|
|
||||||
"Int32": types.Int32,
|
|
||||||
"Int16": types.Int16,
|
|
||||||
"Int8": types.Int8,
|
|
||||||
"Float": types.Float,
|
|
||||||
"Float64": types.Float64,
|
|
||||||
"Float32": types.Float32,
|
|
||||||
"Pointer": types.PointerAny,
|
|
||||||
}
|
|
||||||
|
|
||||||
for functions != nil || files != nil || errs != nil {
|
for functions != nil || files != nil || errs != nil {
|
||||||
select {
|
select {
|
||||||
@ -36,16 +25,16 @@ func Compile(files <-chan *fs.File, functions <-chan *core.Function, structs <-c
|
|||||||
}
|
}
|
||||||
|
|
||||||
function.Functions = allFunctions
|
function.Functions = allFunctions
|
||||||
function.Types = allTypes
|
function.Structs = allStructs
|
||||||
allFunctions[function.UniqueName] = function
|
allFunctions[function.UniqueName] = function
|
||||||
|
|
||||||
case typ, ok := <-structs:
|
case structure, ok := <-structs:
|
||||||
if !ok {
|
if !ok {
|
||||||
structs = nil
|
structs = nil
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
allTypes[typ.Name()] = typ
|
allStructs[structure.UniqueName] = structure
|
||||||
|
|
||||||
case file, ok := <-files:
|
case file, ok := <-files:
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -66,14 +55,8 @@ func Compile(files <-chan *fs.File, functions <-chan *core.Function, structs <-c
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate size of structs
|
// Calculate size of structs
|
||||||
for _, typ := range allTypes {
|
for _, structure := range allStructs {
|
||||||
structure, isStruct := typ.(*types.Struct)
|
structure.Update(allStructs)
|
||||||
|
|
||||||
if !isStruct {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
structure.Update(allTypes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the types
|
// Resolve the types
|
||||||
|
@ -30,15 +30,15 @@ func (f *Function) CompileCall(root *expression.Expression) (*Function, error) {
|
|||||||
case "syscall":
|
case "syscall":
|
||||||
return nil, f.CompileSyscall(root)
|
return nil, f.CompileSyscall(root)
|
||||||
case "new":
|
case "new":
|
||||||
|
typ, err := f.CompileNew(root)
|
||||||
|
|
||||||
return &Function{
|
return &Function{
|
||||||
Output: []*Output{
|
Output: []*Output{
|
||||||
{
|
{
|
||||||
Type: &types.Pointer{
|
Type: typ,
|
||||||
To: f.Types[root.Children[1].Token.Text(f.File.Bytes)],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}, err
|
||||||
}, f.CompileNew(root)
|
|
||||||
case "delete":
|
case "delete":
|
||||||
return nil, f.CompileDelete(root)
|
return nil, f.CompileDelete(root)
|
||||||
case "store":
|
case "store":
|
||||||
|
@ -2,16 +2,49 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.akyoto.dev/cli/q/src/asm"
|
"git.akyoto.dev/cli/q/src/asm"
|
||||||
|
"git.akyoto.dev/cli/q/src/errors"
|
||||||
"git.akyoto.dev/cli/q/src/expression"
|
"git.akyoto.dev/cli/q/src/expression"
|
||||||
|
"git.akyoto.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CompileNew compiles a `new` function call which allocates a struct.
|
// CompileNew compiles a `new` function call which allocates a struct.
|
||||||
func (f *Function) CompileNew(root *expression.Expression) error {
|
func (f *Function) CompileNew(root *expression.Expression) (types.Type, error) {
|
||||||
parameters := root.Children[1:]
|
var (
|
||||||
structName := parameters[0].Token.Text(f.File.Bytes)
|
parameters = root.Children[1:]
|
||||||
typ := f.Types[structName]
|
nameNode = parameters[0]
|
||||||
|
pkg = f.Package
|
||||||
|
name string
|
||||||
|
)
|
||||||
|
|
||||||
|
if nameNode.IsLeaf() {
|
||||||
|
name = nameNode.Token.Text(f.File.Bytes)
|
||||||
|
} else {
|
||||||
|
pkg = nameNode.Children[0].Token.Text(f.File.Bytes)
|
||||||
|
name = nameNode.Children[1].Token.Text(f.File.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg != f.File.Package {
|
||||||
|
if f.File.Imports == nil {
|
||||||
|
return nil, errors.New(&errors.UnknownPackage{Name: pkg}, f.File, nameNode.Token.Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
imp, exists := f.File.Imports[pkg]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return nil, errors.New(&errors.UnknownPackage{Name: pkg}, f.File, nameNode.Token.Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
imp.Used = true
|
||||||
|
}
|
||||||
|
|
||||||
|
typ, exists := f.Structs[pkg+"."+name]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return nil, errors.New(&errors.UnknownType{Name: name}, f.File, nameNode.Token.Position)
|
||||||
|
}
|
||||||
|
|
||||||
f.SaveRegister(f.CPU.Input[0])
|
f.SaveRegister(f.CPU.Input[0])
|
||||||
f.RegisterNumber(asm.MOVE, f.CPU.Input[0], typ.Size())
|
f.RegisterNumber(asm.MOVE, f.CPU.Input[0], typ.Size())
|
||||||
f.CallSafe(f.Functions["mem.alloc"], f.CPU.Input[:1])
|
f.CallSafe(f.Functions["mem.alloc"], f.CPU.Input[:1])
|
||||||
return nil
|
return &types.Pointer{To: typ}, nil
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ type Function struct {
|
|||||||
Input []*Input
|
Input []*Input
|
||||||
Output []*Output
|
Output []*Output
|
||||||
Functions map[string]*Function
|
Functions map[string]*Function
|
||||||
Types map[string]types.Type
|
Structs map[string]*types.Struct
|
||||||
DLLs dll.List
|
DLLs dll.List
|
||||||
Err error
|
Err error
|
||||||
deferred []func()
|
deferred []func()
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/errors"
|
"git.akyoto.dev/cli/q/src/errors"
|
||||||
"git.akyoto.dev/cli/q/src/scope"
|
"git.akyoto.dev/cli/q/src/scope"
|
||||||
"git.akyoto.dev/cli/q/src/token"
|
"git.akyoto.dev/cli/q/src/token"
|
||||||
|
"git.akyoto.dev/cli/q/src/types"
|
||||||
"git.akyoto.dev/cli/q/src/x86"
|
"git.akyoto.dev/cli/q/src/x86"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ func (f *Function) ResolveTypes() error {
|
|||||||
for i, param := range f.Input {
|
for i, param := range f.Input {
|
||||||
param.Name = param.tokens[0].Text(f.File.Bytes)
|
param.Name = param.tokens[0].Text(f.File.Bytes)
|
||||||
typeName := param.tokens[1:].Text(f.File.Bytes)
|
typeName := param.tokens[1:].Text(f.File.Bytes)
|
||||||
param.Type = f.TypeByName(typeName)
|
param.Type = types.ByName(typeName, f.Package, f.Structs)
|
||||||
|
|
||||||
if param.Type == nil {
|
if param.Type == nil {
|
||||||
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[1].Position)
|
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[1].Position)
|
||||||
@ -34,7 +35,7 @@ func (f *Function) ResolveTypes() error {
|
|||||||
|
|
||||||
for _, param := range f.Output {
|
for _, param := range f.Output {
|
||||||
typeName := param.tokens.Text(f.File.Bytes)
|
typeName := param.tokens.Text(f.File.Bytes)
|
||||||
param.Type = f.TypeByName(typeName)
|
param.Type = types.ByName(typeName, f.Package, f.Structs)
|
||||||
|
|
||||||
if param.Type == nil {
|
if param.Type == nil {
|
||||||
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[1].Position)
|
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[1].Position)
|
||||||
|
@ -1,17 +1 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.akyoto.dev/cli/q/src/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TypeByName returns the type with the given name or `nil` if it doesn't exist.
|
|
||||||
func (f *Function) TypeByName(name string) types.Type {
|
|
||||||
if strings.HasPrefix(name, "*") {
|
|
||||||
to := strings.TrimPrefix(name, "*")
|
|
||||||
return &types.Pointer{To: f.TypeByName(to)}
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.Types[name]
|
|
||||||
}
|
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Scan scans the list of files.
|
// Scan scans the list of files.
|
||||||
func Scan(files []string) (<-chan *fs.File, <-chan *core.Function, <-chan types.Type, <-chan error) {
|
func Scan(files []string) (<-chan *fs.File, <-chan *core.Function, <-chan *types.Struct, <-chan error) {
|
||||||
scanner := Scanner{
|
scanner := Scanner{
|
||||||
files: make(chan *fs.File),
|
files: make(chan *fs.File),
|
||||||
functions: make(chan *core.Function),
|
functions: make(chan *core.Function),
|
||||||
types: make(chan types.Type),
|
structs: make(chan *types.Struct),
|
||||||
errors: make(chan error),
|
errors: make(chan error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,9 +24,9 @@ func Scan(files []string) (<-chan *fs.File, <-chan *core.Function, <-chan types.
|
|||||||
scanner.group.Wait()
|
scanner.group.Wait()
|
||||||
close(scanner.files)
|
close(scanner.files)
|
||||||
close(scanner.functions)
|
close(scanner.functions)
|
||||||
close(scanner.types)
|
close(scanner.structs)
|
||||||
close(scanner.errors)
|
close(scanner.errors)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return scanner.files, scanner.functions, scanner.types, scanner.errors
|
return scanner.files, scanner.functions, scanner.structs, scanner.errors
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
files chan *fs.File
|
files chan *fs.File
|
||||||
functions chan *core.Function
|
functions chan *core.Function
|
||||||
types chan types.Type
|
structs chan *types.Struct
|
||||||
errors chan error
|
errors chan error
|
||||||
queued sync.Map
|
queued sync.Map
|
||||||
group sync.WaitGroup
|
group sync.WaitGroup
|
||||||
|
@ -16,7 +16,7 @@ func (s *Scanner) scanStruct(file *fs.File, tokens token.List, i int) (int, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
structName := tokens[i].Text(file.Bytes)
|
structName := tokens[i].Text(file.Bytes)
|
||||||
structure := types.NewStruct(structName)
|
structure := types.NewStruct(file.Package, structName)
|
||||||
|
|
||||||
i++
|
i++
|
||||||
|
|
||||||
@ -54,6 +54,6 @@ func (s *Scanner) scanStruct(file *fs.File, tokens token.List, i int) (int, erro
|
|||||||
return i, errors.New(errors.MissingBlockEnd, file, tokens[i].Position)
|
return i, errors.New(errors.MissingBlockEnd, file, tokens[i].Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.types <- structure
|
s.structs <- structure
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
36
src/types/ByName.go
Normal file
36
src/types/ByName.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ByName returns the type with the given name or `nil` if it doesn't exist.
|
||||||
|
func ByName(name string, pkg string, structs map[string]*Struct) Type {
|
||||||
|
if strings.HasPrefix(name, "*") {
|
||||||
|
to := strings.TrimPrefix(name, "*")
|
||||||
|
return &Pointer{To: ByName(to, pkg, structs)}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch name {
|
||||||
|
case "Int":
|
||||||
|
return Int
|
||||||
|
case "Int64":
|
||||||
|
return Int64
|
||||||
|
case "Int32":
|
||||||
|
return Int32
|
||||||
|
case "Int16":
|
||||||
|
return Int16
|
||||||
|
case "Int8":
|
||||||
|
return Int8
|
||||||
|
case "Float":
|
||||||
|
return Float
|
||||||
|
case "Float64":
|
||||||
|
return Float64
|
||||||
|
case "Float32":
|
||||||
|
return Float32
|
||||||
|
case "Pointer":
|
||||||
|
return PointerAny
|
||||||
|
}
|
||||||
|
|
||||||
|
return structs[pkg+"."+name]
|
||||||
|
}
|
@ -2,14 +2,20 @@ package types
|
|||||||
|
|
||||||
// Struct is a structure in memory whose regions are addressable with named fields.
|
// Struct is a structure in memory whose regions are addressable with named fields.
|
||||||
type Struct struct {
|
type Struct struct {
|
||||||
|
Package string
|
||||||
|
UniqueName string
|
||||||
name string
|
name string
|
||||||
fields []*Field
|
fields []*Field
|
||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStruct creates a new struct.
|
// NewStruct creates a new struct.
|
||||||
func NewStruct(name string) *Struct {
|
func NewStruct(pkg string, name string) *Struct {
|
||||||
return &Struct{name: name}
|
return &Struct{
|
||||||
|
Package: pkg,
|
||||||
|
UniqueName: pkg + "." + name,
|
||||||
|
name: name,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddField adds a new field to the end of the struct.
|
// AddField adds a new field to the end of the struct.
|
||||||
@ -39,11 +45,11 @@ func (s *Struct) Size() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the offsets and structure size.
|
// Update updates the offsets and structure size.
|
||||||
func (s *Struct) Update(types map[string]Type) {
|
func (s *Struct) Update(allTypes map[string]*Struct) {
|
||||||
s.size = 0
|
s.size = 0
|
||||||
|
|
||||||
for _, field := range s.fields {
|
for _, field := range s.fields {
|
||||||
field.Type = types[field.TypeName]
|
field.Type = ByName(field.TypeName, s.Package, allTypes)
|
||||||
field.Offset = s.size
|
field.Offset = s.size
|
||||||
s.size += field.Type.Size()
|
s.size += field.Type.Size()
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,12 @@ func TestSize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStruct(t *testing.T) {
|
func TestStruct(t *testing.T) {
|
||||||
s := types.NewStruct("Test")
|
s := types.NewStruct("main", "Test")
|
||||||
assert.Equal(t, s.Name(), "Test")
|
assert.Equal(t, s.Name(), "Test")
|
||||||
assert.Equal(t, s.Size(), 0)
|
assert.Equal(t, s.Size(), 0)
|
||||||
field := &types.Field{Name: "TestField", TypeName: "Int8"}
|
field := &types.Field{Name: "TestField", TypeName: "Int8"}
|
||||||
s.AddField(field)
|
s.AddField(field)
|
||||||
s.Update(map[string]types.Type{"Int8": types.Int8})
|
s.Update(nil)
|
||||||
assert.Equal(t, s.Size(), 1)
|
assert.Equal(t, s.Size(), 1)
|
||||||
assert.Equal(t, s.FieldByName("TestField"), field)
|
assert.Equal(t, s.FieldByName("TestField"), field)
|
||||||
assert.Nil(t, s.FieldByName("does-not-exist"))
|
assert.Nil(t, s.FieldByName("does-not-exist"))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user