Advertisement
Ladies_Man

#COMPLR Lab2 (Go Trees) COMPLETE

Mar 1st, 2016
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 8.99 KB | None | 0 0
  1. //Л.Р.2 Синтаксические деревья
  2.  
  3. //demo.go
  4. package main
  5.  
  6. import (
  7.     "fmt"
  8.     "go/ast"
  9.     "go/format"
  10.     "go/parser"
  11.     "go/token"
  12.     "io/ioutil"
  13.     "os"
  14.     "sort"
  15. )
  16.  
  17. type storage struct {
  18.     _type *ast.FuncType
  19.     _body *ast.BlockStmt
  20. }
  21.  
  22. //=====================================================
  23. //-----------------GLOBAL-FUNCTION---------------------
  24. //=====================================================
  25.  
  26. func insertFunc(file *ast.File, name string, intrails storage) {
  27.  
  28.     //compose function of intrails and name
  29.     new_func := &ast.FuncDecl{
  30.         Doc:  nil,
  31.         Recv: nil,
  32.         Name: &ast.Ident{
  33.             NamePos: token.NoPos,
  34.             Name:    name,
  35.         },
  36.         Type: intrails._type,
  37.         Body: intrails._body,
  38.     }
  39.  
  40.     //add it to the back
  41.     file.Decls = append(file.Decls, new_func)
  42. }
  43.  
  44. //=====================================================
  45. //----------------------IMPORT-------------------------
  46. //=====================================================
  47.  
  48. func insertImport(file *ast.File, import_name string) {
  49.  
  50.     //import was previusly deleted by ast.FilterFile()
  51.     new_impt := &ast.GenDecl{
  52.         Doc:    nil,
  53.         TokPos: token.NoPos,
  54.         Tok:    token.IMPORT,
  55.         Lparen: token.NoPos,
  56.         Specs: []ast.Spec{
  57.             &ast.ImportSpec{
  58.                 Doc:  nil,
  59.                 Name: nil,
  60.                 Path: &ast.BasicLit{
  61.                     Kind:  token.STRING,
  62.                     Value: "\"" + import_name + "\"",
  63.                 },
  64.                 Comment: nil,
  65.             },
  66.         },
  67.         Rparen: token.NoPos,
  68.     }
  69.  
  70.     var before, after []ast.Decl
  71.  
  72.     if len(file.Decls) > 0 {
  73.         hasImport := false
  74.         if genDecl, ok := file.Decls[0].(*ast.GenDecl); ok {
  75.             hasImport = genDecl.Tok == token.IMPORT
  76.         }
  77.  
  78.         if hasImport {
  79.             before, after = []ast.Decl{file.Decls[0]}, file.Decls[1:]
  80.         } else {
  81.             after = file.Decls
  82.         }
  83.     }
  84.  
  85.     //post it to the beginning
  86.     file.Decls = append(before, new_impt)
  87.     file.Decls = append(file.Decls, after...)
  88. }
  89.  
  90. //=====================================================
  91. //---------------------INT-var-------------------------
  92. //=====================================================
  93.  
  94. func insertIntVar(file *ast.File, name string, value int) {
  95.     var before, after []ast.Decl
  96.  
  97.     if len(file.Decls) > 0 {
  98.         hasImport := false
  99.         if genDecl, ok := file.Decls[0].(*ast.GenDecl); ok {
  100.             hasImport = genDecl.Tok == token.IMPORT
  101.         }
  102.  
  103.         if hasImport {
  104.             before, after = []ast.Decl{file.Decls[0]}, file.Decls[1:]
  105.         } else {
  106.             after = file.Decls
  107.         }
  108.     }
  109.  
  110.     file.Decls = append(before,
  111.         &ast.GenDecl{
  112.             Tok: token.VAR,
  113.             Specs: []ast.Spec{
  114.                 &ast.ValueSpec{
  115.                     Names: []*ast.Ident{ast.NewIdent(name)},
  116.                     Type:  ast.NewIdent("int"),
  117.                     Values: []ast.Expr{
  118.                         &ast.BasicLit{
  119.                             Kind:  token.INT,
  120.                             Value: fmt.Sprintf("%d", value),
  121.                         },
  122.                     },
  123.                 },
  124.             },
  125.         },
  126.     )
  127.  
  128.     file.Decls = append(file.Decls, after...)
  129.  
  130. }
  131.  
  132. //=====================================================
  133. //-----------------------CONST-------------------------
  134. //=====================================================
  135.  
  136. func insertConst(file *ast.File, name string, value string) {
  137.  
  138.     var before, after []ast.Decl
  139.  
  140.     if len(file.Decls) > 0 {
  141.         hasImport := false
  142.         if genDecl, ok := file.Decls[0].(*ast.GenDecl); ok {
  143.             hasImport = genDecl.Tok == token.IMPORT
  144.         }
  145.  
  146.         if hasImport {
  147.             before, after = []ast.Decl{file.Decls[0]}, file.Decls[1:]
  148.         } else {
  149.             after = file.Decls
  150.         }
  151.     }
  152.  
  153.     file.Decls = append(before,
  154.         &ast.GenDecl{
  155.             Tok: token.CONST,
  156.             Specs: []ast.Spec{
  157.                 &ast.ValueSpec{
  158.                     Doc:   nil,
  159.                     Names: []*ast.Ident{ast.NewIdent(name)},
  160.                     Type:  nil,
  161.                     Values: []ast.Expr{
  162.                         &ast.BasicLit{
  163.                             Kind:  token.STRING,
  164.                             Value: "\"" + value + "\"",
  165.                         },
  166.                     },
  167.                     Comment: nil,
  168.                 },
  169.             },
  170.         },
  171.     )
  172.  
  173.     file.Decls = append(file.Decls, after...)
  174. }
  175.  
  176. //=====================================================
  177. //------------------Printf(hello)----------------------
  178. //=====================================================
  179.  
  180. func insertHello(file *ast.File) {
  181.     ast.Inspect(file, func(node ast.Node) bool {
  182.         if ifStmt, ok := node.(*ast.IfStmt); ok {
  183.             ifStmt.Body.List = append(
  184.                 []ast.Stmt{
  185.                     &ast.ExprStmt{
  186.                         X: &ast.CallExpr{
  187.                             Fun: &ast.SelectorExpr{
  188.                                 X:   ast.NewIdent("fmt"),
  189.                                 Sel: ast.NewIdent("Printf"),
  190.                             },
  191.                             Args: []ast.Expr{
  192.                                 &ast.BasicLit{
  193.                                     Kind:  token.CONST,
  194.                                     Value: "\"hello\"",
  195.                                 },
  196.                             },
  197.                         },
  198.                     },
  199.                 },
  200.                 ifStmt.Body.List...,
  201.             )
  202.         }
  203.         return true
  204.     })
  205. }
  206.  
  207. func modify_tree(file *ast.File, fs *token.FileSet, src []byte) {
  208.  
  209.     str := string(src)
  210.     m_cont := make(map[string]storage) //functions map [func_name]<func_body as container>
  211.  
  212.     ast.Inspect(file, func(node ast.Node) bool {
  213.  
  214.         switch x := node.(type) {
  215.  
  216.         case *ast.FuncDecl:
  217.  
  218.             //Вар 6
  219.             //Объявления глобальных функций должны располагаться
  220.             //в конце программы в алфавитном порядке
  221.  
  222.             func_name := x.Name.Name
  223.             func_itself := x.Body
  224.             func_type := x.Type
  225.  
  226.             //save some info about function
  227.             func_start_offs := fs.Position(func_itself.Pos()).Offset
  228.             func_end_offs := fs.Position(func_itself.End()).Offset
  229.             func_line := fs.Position(func_itself.Pos()).Line
  230.             func_filename := fs.Position(func_itself.Pos()).Filename
  231.             func_body := str[func_start_offs:func_end_offs]
  232.  
  233.             if "main" != func_name {
  234.  
  235.                 t := storage{func_type, func_itself}
  236.                 m_cont[func_name] = t
  237.  
  238.                 fmt.Printf("FuncName:[%s]\nFileName:[%s]\nLine:[%d] Offset:[%d..%d]\n FuncBody:[%s]\n",
  239.                     func_name, func_filename, func_line, func_start_offs, func_end_offs, func_body)
  240.             }
  241.  
  242.         }
  243.  
  244.         return true
  245.     })
  246.  
  247.  
  248.     //remove all nodes (global functions) that were previously found and saved to map
  249.     for key, _ := range m_cont {
  250.  
  251.         remove_node(file, key)
  252.     }
  253.  
  254.  
  255.     //sort func_names alphabetically
  256.     sorted := make([]string, len(m_cont))
  257.     i := 0
  258.  
  259.     for k, _ := range m_cont {
  260.         sorted[i] = k
  261.         i++
  262.     }
  263.     sort.Strings(sorted)
  264.  
  265.  
  266.     //add functions to the back
  267.     for i := 0; i < len(m_cont); i++ {
  268.  
  269.         name := sorted[i]
  270.         body := m_cont[name]
  271.         insertFunc(file, name, body)
  272.  
  273.         fmt.Printf("Func [%s] were added\n", name)
  274.     }
  275.  
  276.  
  277.     //restore Import statemnt that was deleted by ast.FilterFile()
  278.     insertImport(file, "fmt")
  279.  
  280. }
  281.  
  282. //=====================================================
  283. //--------------------REMOVE-NODE----------------------
  284. //=====================================================
  285.  
  286. func remove_node(file *ast.File, name string) {
  287.     //as said in filter.go:
  288.     // FilterFile trims the AST for a Go file in place by removing all
  289.     // names from top-level declarations that don't pass through the filter f...
  290.     // Import declarations are always removed.
  291.     ast.FilterFile(file, func(ident string) bool {
  292.         println("Testing filter for: ", ident)
  293.         //keep all elements that dont match the name
  294.         return ident != name
  295.     })
  296. }
  297.  
  298. func main() {
  299.     if len(os.Args) != 2 {
  300.         fmt.Printf("usage: demo.exe <filename.go>\n")
  301.         return
  302.     }
  303.  
  304.     // Создаём хранилище данных об исходных файлах
  305.     fset := token.NewFileSet()
  306.     // Сохраняем исходный файл как строку
  307.     src, err := ioutil.ReadFile(os.Args[1])
  308.  
  309.     if nil != err {
  310.         fmt.Printf("error reading file!\n")
  311.     }
  312.  
  313.     // Вызываем парсер
  314.     if file, err := parser.ParseFile(
  315.         fset,                 // данные об исходниках
  316.         os.Args[1],           // имя файла с исходником программы
  317.         src,                  // передаем файл в виде строки
  318.         parser.ParseComments, // приказываем сохранять комментарии
  319.     ); err == nil {
  320.         // Если парсер отработал без ошибок, печатаем дерево
  321.         //insertIntVar(file, "xxx", 666)
  322.         //insertHello(file)
  323.         modify_tree(file, fset, src)
  324.  
  325.         if format.Node(os.Stdout, fset, file) != nil {
  326.             fmt.Printf("Formatter error: %v\n", err)
  327.         }
  328.  
  329.         //ast.Fprint(os.Stdout, fset, file, nil)
  330.  
  331.         // Собираем файл из модифицированного дерева
  332.         tmp := string(os.Args[1])
  333.         f, _ := os.Create(tmp[:len(tmp)-3] + "_MOD.go")
  334.         format.Node(f, fset, file)
  335.  
  336.         fmt.Printf("%s_MOD.go has been created\n", tmp[:len(tmp)-3])
  337.  
  338.     } else {
  339.         // в противном случае, выводим сообщение об ошибке
  340.         fmt.Printf("Error: %v", err)
  341.     }
  342. }
  343.  
  344.  
  345.  
  346.  
  347.  
  348. //INPUT EXAMPLE
  349. //hello.go
  350. package main
  351.  
  352. import "fmt"
  353.  
  354. func stark(x int) int {
  355.     return x * 1337
  356. }
  357.  
  358. func mark(a int) int {
  359.     return a + 1
  360. }
  361.  
  362. func main() {
  363.     const abc = "DEF"
  364.     fmt.Printf("hello, world\n")
  365.     var j int
  366.     j = 5
  367.     if j < 3 {
  368.         j++
  369.     }
  370.     //greetings
  371.     j = mark(j)
  372.     fmt.Printf("J=%d\n", j)
  373. }
  374.  
  375.  
  376.  
  377.  
  378. //OUTPUT EXAMPLE
  379. //hello_MOD.go
  380. package main
  381.  
  382. import "fmt"
  383.  
  384. func main() {
  385.     const abc = "DEF"
  386.     fmt.Printf("hello, world\n")
  387.     var j int
  388.     j = 5
  389.     if j < 3 {
  390.         j++
  391.     }
  392.     //greetings
  393.     j = mark(j)
  394.     fmt.Printf("J=%d\n", j)
  395. }
  396. func mark(a int) int {
  397.     return a + 1
  398. }
  399. func stark(x int) int {
  400.     return x * 1337
  401. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement