Improved code layout
This commit is contained in:
parent
2c6999040d
commit
1058970be3
@ -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.
|
||||||
|
@ -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{
|
||||||
@ -151,9 +147,10 @@ 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:]
|
||||||
|
|
||||||
@ -191,12 +188,38 @@ func (f *Function) CompileInstruction(line token.List) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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() == "λ"
|
||||||
|
}
|
||||||
|
@ -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 {
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user