// parseConstants finds constant definitions and references to them. // It replaces the references with the nodes denoting the value of // the respective constants. func parseConstants(ast *parser.AST, list []parser.Node) (out []parser.Node, err error) { var instr *parser.Instruction var expr *parser.Expression var name *parser.Name var ok bool consts := make(map[string][]parser.Node) for i := 0; i < len(list); i++ { if instr, ok = list[i].(*parser.Instruction); !ok { continue } name = instr.Children()[0].(*parser.Name) if name.Data != "equ" { continue } expr = instr.Children()[1].(*parser.Expression) name = expr.Children()[0].(*parser.Name) if _, ok = consts[name.Data]; ok { return nil, NewBuildError( ast.Files[instr.File()], instr.Line(), instr.Col(), "Duplicate constant %q.", name.Data) } expr = instr.Children()[2].(*parser.Expression) consts[name.Data] = expr.Children() // Remove constant node from AST. copy(list[i:], list[i+1:]) list = list[:len(list)-1] i-- } for k, v := range consts { list = replaceConstantRef(list, k, v) } return list, nil }
// fixFunctionReturns finds 'return' instructions and replaces them // with appropriate `set pc, $__<name>_epilog` versions. func fixFunctionReturns(ast *parser.AST, f *parser.Function) { var instr *parser.Instruction var expr *parser.Expression var file, line, col int var code []parser.Node var ok bool name := f.Children()[0].(*parser.Name) exitLabel := "$__" + name.Data + "_epilog" list := f.Children()[1:] for i := range list { if instr, ok = list[i].(*parser.Instruction); !ok { continue } code = instr.Children() name = code[0].(*parser.Name) if name.Data != "return" { continue } file, line, col = instr.File(), instr.Line(), instr.Col() name.Data = "set" code = append(code, nil, nil) expr = parser.NewExpression(file, line, col) expr.SetChildren([]parser.Node{ parser.NewName(file, line, col, "pc"), }) code[1] = expr expr = parser.NewExpression(file, line, col) expr.SetChildren([]parser.Node{ parser.NewName(file, line, col, exitLabel), }) code[2] = expr instr.SetChildren(code) } }