Implemented structs
This commit is contained in:
@ -26,6 +26,10 @@ func (f *Function) CompileAssign(node *ast.Assign) error {
|
||||
return f.Execute(operator, variable.Register, right)
|
||||
}
|
||||
|
||||
if left.Token.Kind == token.Period {
|
||||
return f.CompileAssignField(node)
|
||||
}
|
||||
|
||||
if left.Token.Kind == token.Array {
|
||||
return f.CompileAssignArray(node)
|
||||
}
|
||||
|
44
src/core/CompileAssignField.go
Normal file
44
src/core/CompileAssignField.go
Normal file
@ -0,0 +1,44 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/asm"
|
||||
"git.akyoto.dev/cli/q/src/ast"
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
"git.akyoto.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
// CompileAssignField compiles a memory write to a struct field.
|
||||
func (f *Function) CompileAssignField(node *ast.Assign) error {
|
||||
destination := node.Expression.Children[0]
|
||||
value := node.Expression.Children[1]
|
||||
name := destination.Children[0].Token.Text(f.File.Bytes)
|
||||
fieldName := destination.Children[1].Token.Text(f.File.Bytes)
|
||||
variable := f.VariableByName(name)
|
||||
|
||||
if variable == nil {
|
||||
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, destination.Children[0].Token.Position)
|
||||
}
|
||||
|
||||
defer f.UseVariable(variable)
|
||||
pointer := variable.Type.(*types.Pointer)
|
||||
structure := pointer.To.(*types.Struct)
|
||||
|
||||
for _, field := range structure.Fields {
|
||||
if field.Name == fieldName {
|
||||
memory := asm.Memory{
|
||||
Base: variable.Register,
|
||||
Offset: field.Offset,
|
||||
OffsetRegister: math.MaxUint8,
|
||||
Length: field.Type.TotalSize(),
|
||||
}
|
||||
|
||||
_, err := f.ExpressionToMemory(value, memory)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: unknown field error
|
||||
return nil
|
||||
}
|
@ -26,11 +26,20 @@ func (f *Function) CompileCall(root *expression.Expression) (*Function, error) {
|
||||
if nameNode.IsLeaf() {
|
||||
name = nameNode.Token.Text(f.File.Bytes)
|
||||
|
||||
if name == "syscall" {
|
||||
switch name {
|
||||
case "syscall":
|
||||
return nil, f.CompileSyscall(root)
|
||||
}
|
||||
|
||||
if name == "store" {
|
||||
case "new":
|
||||
return &Function{
|
||||
ReturnTypes: []types.Type{
|
||||
&types.Pointer{
|
||||
To: f.Types[root.Children[1].Token.Text(f.File.Bytes)],
|
||||
},
|
||||
},
|
||||
}, f.CompileNew(root)
|
||||
case "delete":
|
||||
return nil, f.CompileDelete(root)
|
||||
case "store":
|
||||
return nil, f.CompileMemoryStore(root)
|
||||
}
|
||||
} else {
|
||||
@ -85,8 +94,8 @@ func (f *Function) CompileCall(root *expression.Expression) (*Function, error) {
|
||||
|
||||
if !types.Check(typ, fn.Parameters[i].Type) {
|
||||
return nil, errors.New(&errors.TypeMismatch{
|
||||
Encountered: typ.Name,
|
||||
Expected: fn.Parameters[i].Type.Name,
|
||||
Encountered: typ.UniqueName(),
|
||||
Expected: fn.Parameters[i].Type.UniqueName(),
|
||||
ParameterName: fn.Parameters[i].Name,
|
||||
}, f.File, parameters[i].Token.Position)
|
||||
}
|
||||
|
37
src/core/CompileDelete.go
Normal file
37
src/core/CompileDelete.go
Normal file
@ -0,0 +1,37 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/asm"
|
||||
"git.akyoto.dev/cli/q/src/expression"
|
||||
"git.akyoto.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
// CompileDelete compiles a `delete` function call which deallocates a struct.
|
||||
func (f *Function) CompileDelete(root *expression.Expression) error {
|
||||
parameters := root.Children[1:]
|
||||
variableName := parameters[0].Token.Text(f.File.Bytes)
|
||||
variable := f.VariableByName(variableName)
|
||||
defer f.UseVariable(variable)
|
||||
f.SaveRegister(f.CPU.Input[0])
|
||||
f.SaveRegister(f.CPU.Input[1])
|
||||
f.RegisterRegister(asm.MOVE, f.CPU.Input[0], variable.Register)
|
||||
f.RegisterNumber(asm.MOVE, f.CPU.Input[1], int(variable.Type.(*types.Pointer).To.TotalSize()))
|
||||
|
||||
for _, register := range f.CPU.General {
|
||||
if f.RegisterIsUsed(register) {
|
||||
f.Register(asm.PUSH, register)
|
||||
}
|
||||
}
|
||||
|
||||
f.Call("mem.free")
|
||||
|
||||
for i := len(f.CPU.General) - 1; i >= 0; i-- {
|
||||
register := f.CPU.General[i]
|
||||
|
||||
if f.RegisterIsUsed(register) {
|
||||
f.Register(asm.POP, register)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -8,7 +8,7 @@ import (
|
||||
"git.akyoto.dev/cli/q/src/expression"
|
||||
)
|
||||
|
||||
// CompileMemoryStore ...
|
||||
// CompileMemoryStore compiles a variable-width store to memory.
|
||||
func (f *Function) CompileMemoryStore(root *expression.Expression) error {
|
||||
parameters := root.Children[1:]
|
||||
name := parameters[0].Token.Text(f.File.Bytes)
|
||||
|
33
src/core/CompileNew.go
Normal file
33
src/core/CompileNew.go
Normal file
@ -0,0 +1,33 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/asm"
|
||||
"git.akyoto.dev/cli/q/src/expression"
|
||||
)
|
||||
|
||||
// CompileNew compiles a `new` function call which allocates a struct.
|
||||
func (f *Function) CompileNew(root *expression.Expression) error {
|
||||
parameters := root.Children[1:]
|
||||
structName := parameters[0].Token.Text(f.File.Bytes)
|
||||
typ := f.Types[structName]
|
||||
f.SaveRegister(f.CPU.Input[0])
|
||||
f.RegisterNumber(asm.MOVE, f.CPU.Input[0], int(typ.TotalSize()))
|
||||
|
||||
for _, register := range f.CPU.General {
|
||||
if f.RegisterIsUsed(register) {
|
||||
f.Register(asm.PUSH, register)
|
||||
}
|
||||
}
|
||||
|
||||
f.Call("mem.alloc")
|
||||
|
||||
for i := len(f.CPU.General) - 1; i >= 0; i-- {
|
||||
register := f.CPU.General[i]
|
||||
|
||||
if f.RegisterIsUsed(register) {
|
||||
f.Register(asm.POP, register)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -27,8 +27,8 @@ func (f *Function) CompileReturn(node *ast.Return) error {
|
||||
|
||||
if !types.Check(typ, f.ReturnTypes[i]) {
|
||||
return errors.New(&errors.TypeMismatch{
|
||||
Encountered: typ.Name,
|
||||
Expected: f.ReturnTypes[i].Name,
|
||||
Encountered: typ.UniqueName(),
|
||||
Expected: f.ReturnTypes[i].UniqueName(),
|
||||
ParameterName: "",
|
||||
IsReturn: true,
|
||||
}, f.File, node.Values[i].Token.Position)
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
// Evaluate evaluates an expression and returns a register that contains the value of the expression.
|
||||
func (f *Function) Evaluate(expr *expression.Expression) (*types.Type, cpu.Register, bool, error) {
|
||||
func (f *Function) Evaluate(expr *expression.Expression) (types.Type, cpu.Register, bool, error) {
|
||||
if expr.Token.Kind == token.Identifier {
|
||||
name := expr.Token.Text(f.File.Bytes)
|
||||
variable := f.VariableByName(name)
|
||||
|
@ -10,21 +10,21 @@ import (
|
||||
)
|
||||
|
||||
// ExpressionToMemory puts the result of an expression into the specified memory address.
|
||||
func (f *Function) ExpressionToMemory(node *expression.Expression, memory asm.Memory) (*types.Type, error) {
|
||||
func (f *Function) ExpressionToMemory(node *expression.Expression, memory asm.Memory) (types.Type, error) {
|
||||
if node.IsLeaf() {
|
||||
if node.Token.Kind == token.Identifier {
|
||||
name := node.Token.Text(f.File.Bytes)
|
||||
variable, function := f.Identifier(name)
|
||||
|
||||
if variable != nil {
|
||||
f.UseVariable(variable)
|
||||
f.MemoryRegister(asm.STORE, memory, variable.Register)
|
||||
return types.Pointer, nil
|
||||
f.UseVariable(variable)
|
||||
return types.PointerAny, nil
|
||||
}
|
||||
|
||||
if function != nil {
|
||||
f.MemoryLabel(asm.STORE, memory, function.UniqueName)
|
||||
return types.Pointer, nil
|
||||
return types.PointerAny, nil
|
||||
}
|
||||
|
||||
return nil, errors.New(&errors.UnknownIdentifier{Name: name}, f.File, node.Token.Position)
|
||||
@ -39,7 +39,7 @@ func (f *Function) ExpressionToMemory(node *expression.Expression, memory asm.Me
|
||||
|
||||
size := byte(sizeof.Signed(int64(number)))
|
||||
|
||||
if size != memory.Length {
|
||||
if size > memory.Length {
|
||||
return nil, errors.New(&errors.NumberExceedsBounds{Number: number, ExpectedSize: memory.Length, Size: size}, f.File, node.Token.Position)
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// ExpressionToRegister puts the result of an expression into the specified register.
|
||||
func (f *Function) ExpressionToRegister(node *expression.Expression, register cpu.Register) (*types.Type, error) {
|
||||
func (f *Function) ExpressionToRegister(node *expression.Expression, register cpu.Register) (types.Type, error) {
|
||||
f.SaveRegister(register)
|
||||
|
||||
if node.IsFolded {
|
||||
@ -72,7 +72,7 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if typ == types.Pointer && right.Token.Kind == token.Identifier && f.VariableByName(right.Token.Text(f.File.Bytes)).Type == types.Pointer {
|
||||
if typ == types.PointerAny && right.Token.Kind == token.Identifier && f.VariableByName(right.Token.Text(f.File.Bytes)).Type == types.PointerAny {
|
||||
typ = types.Int
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,9 @@ type Function struct {
|
||||
File *fs.File
|
||||
Body token.List
|
||||
Parameters []*scope.Variable
|
||||
ReturnTypes []*types.Type
|
||||
ReturnTypes []types.Type
|
||||
Functions map[string]*Function
|
||||
Types map[string]types.Type
|
||||
DLLs dll.List
|
||||
Err error
|
||||
deferred []func()
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
// TokenToRegister moves a token into a register.
|
||||
// It only works with identifiers, numbers and strings.
|
||||
func (f *Function) TokenToRegister(t token.Token, register cpu.Register) (*types.Type, error) {
|
||||
func (f *Function) TokenToRegister(t token.Token, register cpu.Register) (types.Type, error) {
|
||||
switch t.Kind {
|
||||
case token.Identifier:
|
||||
name := t.Text(f.File.Bytes)
|
||||
@ -26,7 +26,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) (*types
|
||||
if function != nil {
|
||||
f.SaveRegister(register)
|
||||
f.RegisterLabel(asm.MOVE, register, function.UniqueName)
|
||||
return types.Pointer, nil
|
||||
return types.PointerAny, nil
|
||||
}
|
||||
|
||||
return nil, errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position)
|
||||
@ -48,7 +48,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) (*types
|
||||
label := f.AddBytes(data)
|
||||
f.SaveRegister(register)
|
||||
f.RegisterLabel(asm.MOVE, register, label)
|
||||
return types.Pointer, nil
|
||||
return types.PointerAny, nil
|
||||
|
||||
default:
|
||||
return nil, errors.New(errors.InvalidExpression, f.File, t.Position)
|
||||
|
Reference in New Issue
Block a user