From 69245caf627fc41d6670868eb4e1b81e75407d06 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Tue, 23 Jul 2024 16:41:21 +0200 Subject: [PATCH] Improved separation of concerns --- src/build/config/config.go | 1 - src/build/core/AddVariable.go | 15 --- src/build/core/Comment.go | 11 -- src/build/core/Compare.go | 4 +- src/build/core/Compile.go | 1 - src/build/core/CompileCall.go | 14 +-- src/build/core/CompileDefinition.go | 4 +- src/build/core/CompileReturn.go | 2 +- src/build/core/Execute.go | 4 +- src/build/core/ExpressionToRegister.go | 11 +- src/build/core/Function.go | 22 ++-- ...dentifierExists.go => IdentifierExists.go} | 4 +- src/build/core/Instructions.go | 103 ------------------ src/build/core/NewFunction.go | 28 ++--- src/build/core/PrintInstructions.go | 4 +- src/build/core/UsesRegister.go | 4 +- src/build/core/VariableByName.go | 8 -- src/build/core/VariableInRegister.go | 17 --- src/build/core/postInstruction.go | 11 -- src/build/scope/Stack.go | 22 ++++ src/build/z/AddLabel.go | 8 ++ src/build/z/Call.go | 7 ++ src/build/z/Comment.go | 8 ++ src/build/z/Compiler.go | 15 +++ src/build/z/Jump.go | 8 ++ src/build/z/MemoryNumber.go | 8 ++ src/build/z/Register.go | 16 +++ src/build/z/RegisterLabel.go | 20 ++++ src/build/z/RegisterNumber.go | 20 ++++ src/build/z/RegisterRegister.go | 24 ++++ src/build/z/Return.go | 6 + src/build/{core => z}/SaveRegister.go | 16 +-- src/build/z/Syscall.go | 7 ++ src/build/z/isDestructive.go | 12 ++ src/build/z/postInstruction.go | 11 ++ src/cli/Build.go | 3 - 36 files changed, 243 insertions(+), 236 deletions(-) delete mode 100644 src/build/core/AddVariable.go delete mode 100644 src/build/core/Comment.go rename src/build/core/{identifierExists.go => IdentifierExists.go} (54%) delete mode 100644 src/build/core/Instructions.go delete mode 100644 src/build/core/VariableByName.go delete mode 100644 src/build/core/VariableInRegister.go delete mode 100644 src/build/core/postInstruction.go create mode 100644 src/build/z/AddLabel.go create mode 100644 src/build/z/Call.go create mode 100644 src/build/z/Comment.go create mode 100644 src/build/z/Compiler.go create mode 100644 src/build/z/Jump.go create mode 100644 src/build/z/MemoryNumber.go create mode 100644 src/build/z/Register.go create mode 100644 src/build/z/RegisterLabel.go create mode 100644 src/build/z/RegisterNumber.go create mode 100644 src/build/z/RegisterRegister.go create mode 100644 src/build/z/Return.go rename src/build/{core => z}/SaveRegister.go (63%) create mode 100644 src/build/z/Syscall.go create mode 100644 src/build/z/isDestructive.go create mode 100644 src/build/z/postInstruction.go diff --git a/src/build/config/config.go b/src/build/config/config.go index 0697fa1..99791d2 100644 --- a/src/build/config/config.go +++ b/src/build/config/config.go @@ -16,6 +16,5 @@ const ( var ( Assembler = false - Comments = false Dry = false ) diff --git a/src/build/core/AddVariable.go b/src/build/core/AddVariable.go deleted file mode 100644 index b04ed1f..0000000 --- a/src/build/core/AddVariable.go +++ /dev/null @@ -1,15 +0,0 @@ -package core - -import ( - "git.akyoto.dev/cli/q/src/build/config" - "git.akyoto.dev/cli/q/src/build/scope" -) - -// AddVariable adds a new variable to the current scope. -func (f *Function) AddVariable(variable *scope.Variable) { - if config.Comments { - f.Comment("%s = %s (%d uses)", variable.Name, variable.Register, variable.Alive) - } - - f.CurrentScope().AddVariable(variable) -} diff --git a/src/build/core/Comment.go b/src/build/core/Comment.go deleted file mode 100644 index d5f0590..0000000 --- a/src/build/core/Comment.go +++ /dev/null @@ -1,11 +0,0 @@ -package core - -import ( - "fmt" -) - -// Comment adds a comment to the assembler. -func (f *Function) Comment(format string, args ...any) { - f.Assembler.Comment(fmt.Sprintf(format, args...)) - f.postInstruction() -} diff --git a/src/build/core/Compare.go b/src/build/core/Compare.go index 4351c4a..7eb92f7 100644 --- a/src/build/core/Compare.go +++ b/src/build/core/Compare.go @@ -31,10 +31,10 @@ func (f *Function) Compare(comparison *expression.Expression) error { return err } - return f.Execute(comparison.Token, f.cpu.Output[0], right) + return f.Execute(comparison.Token, f.CPU.Output[0], right) } - tmp := f.CurrentScope().MustFindFree(f.cpu.General) + tmp := f.CurrentScope().MustFindFree(f.CPU.General) err := f.ExpressionToRegister(left, tmp) if err != nil { diff --git a/src/build/core/Compile.go b/src/build/core/Compile.go index 4c2cb94..41c079d 100644 --- a/src/build/core/Compile.go +++ b/src/build/core/Compile.go @@ -2,7 +2,6 @@ package core // Compile turns a function into machine code. func (f *Function) Compile() { - defer close(f.finished) f.AddLabel(f.Name) f.Err = f.CompileTokens(f.Body) f.Return() diff --git a/src/build/core/CompileCall.go b/src/build/core/CompileCall.go index 3270d01..358d4f8 100644 --- a/src/build/core/CompileCall.go +++ b/src/build/core/CompileCall.go @@ -31,10 +31,10 @@ func (f *Function) CompileCall(root *expression.Expression) error { } parameters := root.Children[1:] - registers := f.cpu.Input[:len(parameters)] + registers := f.CPU.Input[:len(parameters)] if isSyscall { - registers = f.cpu.Syscall[:len(parameters)] + registers = f.CPU.Syscall[:len(parameters)] } err := f.ExpressionsToRegisters(parameters, registers) @@ -43,10 +43,10 @@ func (f *Function) CompileCall(root *expression.Expression) error { return err } - f.SaveRegister(f.cpu.Output[0]) + f.SaveRegister(f.CPU.Output[0]) // Push - for _, register := range f.cpu.General { + for _, register := range f.CPU.General { if f.CurrentScope().IsUsed(register) { f.Register(asm.PUSH, register) } @@ -60,7 +60,7 @@ func (f *Function) CompileCall(root *expression.Expression) error { } for _, register := range registers { - if register == f.cpu.Output[0] && root.Parent != nil { + if register == f.CPU.Output[0] && root.Parent != nil { continue } @@ -68,8 +68,8 @@ func (f *Function) CompileCall(root *expression.Expression) error { } // Pop - for i := len(f.cpu.General) - 1; i >= 0; i-- { - register := f.cpu.General[i] + for i := len(f.CPU.General) - 1; i >= 0; i-- { + register := f.CPU.General[i] if f.CurrentScope().IsUsed(register) { f.Register(asm.POP, register) diff --git a/src/build/core/CompileDefinition.go b/src/build/core/CompileDefinition.go index 716aa28..71745b5 100644 --- a/src/build/core/CompileDefinition.go +++ b/src/build/core/CompileDefinition.go @@ -11,7 +11,7 @@ import ( func (f *Function) CompileDefinition(node *ast.Define) error { name := node.Name.Text(f.File.Bytes) - if f.identifierExists(name) { + if f.IdentifierExists(name) { return errors.New(&errors.VariableAlreadyExists{Name: name}, f.File, node.Name.Position) } @@ -21,7 +21,7 @@ func (f *Function) CompileDefinition(node *ast.Define) error { return errors.New(&errors.UnusedVariable{Name: name}, f.File, node.Name.Position) } - register := f.CurrentScope().MustFindFree(f.cpu.General) + register := f.CurrentScope().MustFindFree(f.CPU.General) f.CurrentScope().Reserve(register) err := f.ExpressionToRegister(node.Value, register) diff --git a/src/build/core/CompileReturn.go b/src/build/core/CompileReturn.go index 57219c4..26f1cab 100644 --- a/src/build/core/CompileReturn.go +++ b/src/build/core/CompileReturn.go @@ -12,5 +12,5 @@ func (f *Function) CompileReturn(node *ast.Return) error { return nil } - return f.ExpressionToRegister(node.Value, f.cpu.Output[0]) + return f.ExpressionToRegister(node.Value, f.CPU.Output[0]) } diff --git a/src/build/core/Execute.go b/src/build/core/Execute.go index f8c8484..09f2dec 100644 --- a/src/build/core/Execute.go +++ b/src/build/core/Execute.go @@ -20,10 +20,10 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value * return err } - return f.ExecuteRegisterRegister(operation, register, f.cpu.Output[0]) + return f.ExecuteRegisterRegister(operation, register, f.CPU.Output[0]) } - tmp := f.CurrentScope().MustFindFree(f.cpu.General) + tmp := f.CurrentScope().MustFindFree(f.CPU.General) defer f.CurrentScope().Free(tmp) err := f.ExpressionToRegister(value, tmp) diff --git a/src/build/core/ExpressionToRegister.go b/src/build/core/ExpressionToRegister.go index f2b2fa1..c900c7b 100644 --- a/src/build/core/ExpressionToRegister.go +++ b/src/build/core/ExpressionToRegister.go @@ -3,7 +3,6 @@ package core import ( "git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/ast" - "git.akyoto.dev/cli/q/src/build/config" "git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/errors" "git.akyoto.dev/cli/q/src/build/expression" @@ -18,8 +17,8 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp if ast.IsFunctionCall(node) { err := f.CompileCall(node) - if register != f.cpu.Output[0] { - f.RegisterRegister(asm.MOVE, register, f.cpu.Output[0]) + if register != f.CPU.Output[0] { + f.RegisterRegister(asm.MOVE, register, f.CPU.Output[0]) } return err @@ -34,11 +33,7 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp final := register if f.UsesRegister(right, register) { - register = f.CurrentScope().MustFindFree(f.cpu.General) - - if config.Comments { - f.Comment("temporary register %s", register) - } + register = f.CurrentScope().MustFindFree(f.CPU.General) } f.CurrentScope().Reserve(register) diff --git a/src/build/core/Function.go b/src/build/core/Function.go index 36ac29d..65b9252 100644 --- a/src/build/core/Function.go +++ b/src/build/core/Function.go @@ -1,26 +1,20 @@ package core import ( - "git.akyoto.dev/cli/q/src/build/asm" - "git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/fs" - "git.akyoto.dev/cli/q/src/build/scope" "git.akyoto.dev/cli/q/src/build/token" + "git.akyoto.dev/cli/q/src/build/z" ) // Function represents the smallest unit of code. type Function struct { - scope.Stack - Name string - File *fs.File - Body []token.Token - Assembler asm.Assembler - Functions map[string]*Function - Err error - registerHistory []uint64 - finished chan struct{} - cpu cpu.CPU - count counter + z.Compiler + Name string + File *fs.File + Body []token.Token + Functions map[string]*Function + Err error + count counter } // counter stores how often a certain statement appeared so we can generate a unique label from it. diff --git a/src/build/core/identifierExists.go b/src/build/core/IdentifierExists.go similarity index 54% rename from src/build/core/identifierExists.go rename to src/build/core/IdentifierExists.go index 96bd55f..efa3ed7 100644 --- a/src/build/core/identifierExists.go +++ b/src/build/core/IdentifierExists.go @@ -1,7 +1,7 @@ package core -// identifierExists returns true if the identifier has been defined. -func (f *Function) identifierExists(name string) bool { +// IdentifierExists returns true if the identifier has been defined. +func (f *Function) IdentifierExists(name string) bool { variable := f.VariableByName(name) if variable != nil { diff --git a/src/build/core/Instructions.go b/src/build/core/Instructions.go deleted file mode 100644 index e06dcff..0000000 --- a/src/build/core/Instructions.go +++ /dev/null @@ -1,103 +0,0 @@ -package core - -import ( - "git.akyoto.dev/cli/q/src/build/asm" - "git.akyoto.dev/cli/q/src/build/cpu" -) - -func (f *Function) AddLabel(label string) { - f.Assembler.Label(asm.LABEL, label) - f.postInstruction() -} - -func (f *Function) Call(label string) { - f.Assembler.Call(label) - f.CurrentScope().Use(f.cpu.Output[0]) - f.postInstruction() -} - -func (f *Function) Jump(mnemonic asm.Mnemonic, label string) { - f.Assembler.Label(mnemonic, label) - f.postInstruction() -} - -func (f *Function) MemoryNumber(mnemonic asm.Mnemonic, a asm.Memory, b int) { - f.Assembler.MemoryNumber(mnemonic, a, b) - f.postInstruction() -} - -func (f *Function) Register(mnemonic asm.Mnemonic, a cpu.Register) { - f.Assembler.Register(mnemonic, a) - - if mnemonic == asm.POP { - f.CurrentScope().Use(a) - } - - f.postInstruction() -} - -func (f *Function) RegisterNumber(mnemonic asm.Mnemonic, a cpu.Register, b int) { - if f.CurrentScope().IsUsed(a) && isDestructive(mnemonic) { - f.SaveRegister(a) - } - - f.Assembler.RegisterNumber(mnemonic, a, b) - - if mnemonic == asm.MOVE { - f.CurrentScope().Use(a) - } - - f.postInstruction() -} - -func (f *Function) RegisterLabel(mnemonic asm.Mnemonic, register cpu.Register, label string) { - if f.CurrentScope().IsUsed(register) && isDestructive(mnemonic) { - f.SaveRegister(register) - } - - f.Assembler.RegisterLabel(mnemonic, register, label) - - if mnemonic == asm.MOVE { - f.CurrentScope().Use(register) - } - - f.postInstruction() -} - -func (f *Function) RegisterRegister(mnemonic asm.Mnemonic, a cpu.Register, b cpu.Register) { - if mnemonic == asm.MOVE && a == b { - return - } - - if f.CurrentScope().IsUsed(a) && isDestructive(mnemonic) { - f.SaveRegister(a) - } - - f.Assembler.RegisterRegister(mnemonic, a, b) - - if mnemonic == asm.MOVE { - f.CurrentScope().Use(a) - } - - f.postInstruction() -} - -func (f *Function) Return() { - f.Assembler.Return() - f.postInstruction() -} - -func (f *Function) Syscall() { - f.Assembler.Syscall() - f.CurrentScope().Use(f.cpu.Output[0]) - f.postInstruction() -} - -func isDestructive(mnemonic asm.Mnemonic) bool { - switch mnemonic { - case asm.MOVE, asm.ADD, asm.SUB, asm.MUL, asm.DIV: - return true - default: - return false - } -} diff --git a/src/build/core/NewFunction.go b/src/build/core/NewFunction.go index 8ad25ba..f73aedb 100644 --- a/src/build/core/NewFunction.go +++ b/src/build/core/NewFunction.go @@ -7,6 +7,7 @@ import ( "git.akyoto.dev/cli/q/src/build/fs" "git.akyoto.dev/cli/q/src/build/scope" "git.akyoto.dev/cli/q/src/build/token" + "git.akyoto.dev/cli/q/src/build/z" ) // NewFunction creates a new function. @@ -15,19 +16,20 @@ func NewFunction(name string, file *fs.File, body []token.Token) *Function { Name: name, File: file, Body: body, - Assembler: asm.Assembler{ - Instructions: make([]asm.Instruction, 0, 8), + Compiler: z.Compiler{ + Assembler: asm.Assembler{ + Instructions: make([]asm.Instruction, 0, 8), + }, + Stack: scope.Stack{ + Scopes: []*scope.Scope{{}}, + }, + CPU: cpu.CPU{ + All: x64.AllRegisters, + Input: x64.CallRegisters, + General: x64.GeneralRegisters, + Syscall: x64.SyscallRegisters, + Output: x64.ReturnValueRegisters, + }, }, - Stack: scope.Stack{ - Scopes: []*scope.Scope{{}}, - }, - cpu: cpu.CPU{ - All: x64.AllRegisters, - Input: x64.CallRegisters, - General: x64.GeneralRegisters, - Syscall: x64.SyscallRegisters, - Output: x64.ReturnValueRegisters, - }, - finished: make(chan struct{}), } } diff --git a/src/build/core/PrintInstructions.go b/src/build/core/PrintInstructions.go index 0c78ba4..a824f3a 100644 --- a/src/build/core/PrintInstructions.go +++ b/src/build/core/PrintInstructions.go @@ -33,9 +33,9 @@ func (f *Function) PrintInstructions() { } registers := bytes.Buffer{} - used := f.registerHistory[i] + used := f.RegisterHistory[i] - for _, reg := range f.cpu.All { + for _, reg := range f.CPU.All { if used&(1<