package build import ( "fmt" "strconv" "git.akyoto.dev/cli/q/src/build/arch/x64" "git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/config" "git.akyoto.dev/cli/q/src/build/token" "git.akyoto.dev/go/color/ansi" ) // Function represents a function. type Function struct { Name string Head token.List Body token.List Variables map[string]*Variable Assembler asm.Assembler } // Compile turns a function into machine code. func (f *Function) Compile() { if config.Verbose { ansi.Underline.Println(f.Name) } for _, line := range f.Lines() { if config.Verbose { fmt.Println("[line]", line) } if len(line) == 0 { continue } if line[0].Kind == token.Keyword { switch line[0].Text() { case "let": name := line[1].Text() value := line[3:] fmt.Println("[variable]", name, value) f.Variables[name] = &Variable{ Value: line[3:], IsConst: true, } case "return": f.Assembler.Return() } } if line[0].Kind == token.Identifier && line[0].Text() == "syscall" { paramTokens := line[2 : len(line)-1] start := 0 i := 0 var parameters []token.List for i < len(paramTokens) { if paramTokens[i].Kind == token.Separator { parameters = append(parameters, paramTokens[start:i]) start = i + 1 } i++ } if i != start { parameters = append(parameters, paramTokens[start:i]) } for i, list := range parameters { switch list[0].Kind { case token.Identifier: name := list[0].Text() variable := f.Variables[name] if !variable.IsConst { panic("Not implemented yet") } n, _ := strconv.Atoi(variable.Value[0].Text()) f.Assembler.MoveRegisterNumber(x64.SyscallArgs[i], uint64(n)) case token.Number: value := list[0].Text() n, _ := strconv.Atoi(value) f.Assembler.MoveRegisterNumber(x64.SyscallArgs[i], uint64(n)) default: panic("Unknown expression") } } f.Assembler.Syscall() } } f.Assembler.Return() } // Lines returns the lines in the function body. func (f *Function) Lines() []token.List { var ( lines []token.List start = 0 i = 0 ) for i < len(f.Body) { if f.Body[i].Kind == token.NewLine { lines = append(lines, f.Body[start:i]) start = i + 1 } i++ } if i != start { lines = append(lines, f.Body[start:i]) } return lines } // String returns the function name. func (f *Function) String() string { return f.Name }