package build import ( "git.akyoto.dev/cli/q/src/build/expression" "git.akyoto.dev/cli/q/src/build/token" "git.akyoto.dev/cli/q/src/errors" ) // CompileVariableDefinition compiles a variable definition. func (f *Function) CompileVariableDefinition(expr *expression.Expression) error { if len(expr.Children) < 2 { return errors.New(errors.MissingAssignValue, f.File, expr.LastChild().Token.End()) } name := expr.Children[0].Token.Text() if f.identifierExists(name) { return errors.New(&errors.VariableAlreadyExists{Name: name}, f.File, expr.Children[0].Token.Position) } reg, exists := f.CPU.FindFree(f.CPU.General) if !exists { panic("no free registers") } err := f.ExpressionToRegister(expr.Children[1], reg) if err != nil { return err } variable := &Variable{ Name: name, Register: reg, } f.addVariable(variable) f.useVariable(variable) return nil } func (f *Function) addVariable(variable *Variable) { variable.UsesRemaining = countIdentifier(f.Body, variable.Name) f.Variables[variable.Name] = variable f.CPU.Use(variable.Register) } func (f *Function) useVariable(variable *Variable) { variable.UsesRemaining-- if variable.UsesRemaining < 0 { panic("incorrect number of variable use calls") } if variable.UsesRemaining == 0 { f.CPU.Free(variable.Register) } } func countIdentifier(tokens token.List, name string) int { count := 0 for _, t := range tokens { if t.Kind == token.Identifier && t.Text() == name { count++ } } return count }