Improved code layout

This commit is contained in:
Eduard Urbach 2024-06-21 12:48:01 +02:00
parent 2c6999040d
commit 1058970be3
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
4 changed files with 133 additions and 110 deletions

View File

@ -19,8 +19,8 @@ func New(files ...string) *Build {
// Run parses the input files and generates an executable file. // Run parses the input files and generates an executable file.
func (build *Build) Run() (map[string]*Function, error) { func (build *Build) Run() (map[string]*Function, error) {
functions, errors := Scan(build.Files) functions, errors := scan(build.Files)
return Compile(functions, errors) return compile(functions, errors)
} }
// Executable returns the path to the executable. // Executable returns the path to the executable.

View File

@ -73,25 +73,6 @@ func (f *Function) Compile() {
f.Assembler.Return() f.Assembler.Return()
} }
// PrintAsm shows the assembly instructions.
func (f *Function) PrintAsm() {
ansi.Bold.Println(f.Name)
ansi.Dim.Println("╭────────────────────────────────────────────────────────────")
for _, x := range f.Assembler.Instructions {
ansi.Dim.Print("│ ")
fmt.Print(x.Mnemonic.String())
if x.Data != nil {
fmt.Print(" " + x.Data.String())
}
fmt.Print("\n")
}
ansi.Dim.Println("╰────────────────────────────────────────────────────────────")
}
// CompileInstruction compiles a single instruction. // CompileInstruction compiles a single instruction.
func (f *Function) CompileInstruction(line token.List) error { func (f *Function) CompileInstruction(line token.List) error {
if len(line) == 0 { if len(line) == 0 {
@ -99,6 +80,30 @@ func (f *Function) CompileInstruction(line token.List) error {
} }
if line[0].Kind == token.Keyword { if line[0].Kind == token.Keyword {
return f.CompileKeyword(line)
}
expr := expression.Parse(line)
if expr == nil {
return nil
}
defer expr.Close()
if isVariableDefinition(expr) {
return f.CompileVariableDefinition(expr)
}
if isFunctionCall(expr) {
return f.CompileFunctionCall(expr)
}
return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position)
}
// CompileKeyword compiles an instruction that starts with a keyword.
func (f *Function) CompileKeyword(line token.List) error {
switch line[0].Text() { switch line[0].Text() {
case "return": case "return":
if len(line) > 1 { if len(line) > 1 {
@ -112,21 +117,12 @@ func (f *Function) CompileInstruction(line token.List) error {
default: default:
return errors.New(&errors.KeywordNotImplemented{Keyword: line[0].Text()}, f.File, line[0].Position) return errors.New(&errors.KeywordNotImplemented{Keyword: line[0].Text()}, f.File, line[0].Position)
} }
}
expr := expression.Parse(line)
if expr == nil {
return nil return nil
} }
defer expr.Close() // CompileVariableDefinition compiles a variable definition.
func (f *Function) CompileVariableDefinition(expr *expression.Expression) error {
if expr.Token.Kind == token.Number || expr.Token.Kind == token.Identifier || expr.Token.Kind == token.String {
return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position)
}
if expr.Token.Text() == ":=" {
if len(expr.Children) < 2 { if len(expr.Children) < 2 {
return errors.New(errors.MissingAssignValue, f.File, expr.LastChild().Token.After()) return errors.New(errors.MissingAssignValue, f.File, expr.LastChild().Token.After())
} }
@ -141,7 +137,7 @@ func (f *Function) CompileInstruction(line token.List) error {
value := expr.Children[1] value := expr.Children[1]
// All expressions are returned to the memory pool. // All expressions are returned to the memory pool.
// To avoid losing variable values, we will remove it from the expression. // To avoid losing variable values, we will detach it from the expression.
expr.RemoveChild(value) expr.RemoveChild(value)
f.Variables[name] = &Variable{ f.Variables[name] = &Variable{
@ -153,7 +149,8 @@ func (f *Function) CompileInstruction(line token.List) error {
return nil return nil
} }
if expr.Token.Text() == "λ" { // CompileFunctionCall compiles a function call.
func (f *Function) CompileFunctionCall(expr *expression.Expression) error {
funcName := expr.Children[0].Token.Text() funcName := expr.Children[0].Token.Text()
parameters := expr.Children[1:] parameters := expr.Children[1:]
@ -193,10 +190,36 @@ func (f *Function) CompileInstruction(line token.List) error {
return nil return nil
} }
return nil // PrintAsm shows the assembly instructions.
func (f *Function) PrintAsm() {
ansi.Bold.Println(f.Name)
ansi.Dim.Println("╭────────────────────────────────────────────────────────────")
for _, x := range f.Assembler.Instructions {
ansi.Dim.Print("│ ")
fmt.Print(x.Mnemonic.String())
if x.Data != nil {
fmt.Print(" " + x.Data.String())
}
fmt.Print("\n")
}
ansi.Dim.Println("╰────────────────────────────────────────────────────────────")
} }
// String returns the function name. // String returns the function name.
func (f *Function) String() string { func (f *Function) String() string {
return f.Name return f.Name
} }
// isVariableDefinition returns true if the expression is a variable definition.
func isVariableDefinition(expr *expression.Expression) bool {
return expr.Token.Kind == token.Operator && expr.Token.Text() == ":="
}
// isFunctionCall returns true if the expression is a function call.
func isFunctionCall(expr *expression.Expression) bool {
return expr.Token.Kind == token.Operator && expr.Token.Text() == "λ"
}

View File

@ -4,8 +4,8 @@ import (
"sync" "sync"
) )
// Compile compiles all the functions. // compile waits for all functions to finish compilation.
func Compile(functions <-chan *Function, errors <-chan error) (map[string]*Function, error) { func compile(functions <-chan *Function, errors <-chan error) (map[string]*Function, error) {
allFunctions := map[string]*Function{} allFunctions := map[string]*Function{}
for functions != nil || errors != nil { for functions != nil || errors != nil {

View File

@ -11,8 +11,8 @@ import (
"git.akyoto.dev/cli/q/src/errors" "git.akyoto.dev/cli/q/src/errors"
) )
// Scan scans the directory. // scan scans the directory.
func Scan(files []string) (<-chan *Function, <-chan error) { func scan(files []string) (<-chan *Function, <-chan error) {
functions := make(chan *Function) functions := make(chan *Function)
errors := make(chan error) errors := make(chan error)