OILS / asdl / metrics.py View on Github | oils.pub

130 lines, 76 significant
1#!/usr/bin/env python2
2"""
3metrics.py
4"""
5from __future__ import print_function
6
7from asdl import visitor
8from asdl import ast
9
10# type checking not turned on yet
11from typing import List, Dict, IO, TYPE_CHECKING
12from asdl.ast import SimpleSum
13from asdl.ast import Sum
14from asdl.ast import SubTypeDecl
15from asdl.ast import Product
16
17if TYPE_CHECKING:
18 from asdl.front_end import TypeLookup
19
20
21class MetricsVisitor(visitor.AsdlVisitor):
22 """Collect metrics"""
23
24 def __init__(self, f):
25 # type: (IO[bytes]) -> None
26 visitor.AsdlVisitor.__init__(self, f)
27
28 def VisitSimpleSum(self, sum, sum_name, depth):
29 # type: (SimpleSum, str, int) -> None
30 pass
31
32 def VisitCompoundSum(self, sum, sum_name, depth):
33 # type: (Sum, str, int) -> None
34 num_variants = 0
35 for i, variant in enumerate(sum.types):
36 if variant.shared_type:
37 continue # Don't generate a class for shared types.
38 num_variants += 1
39 self.f.write('%d %s\n' % (num_variants, sum_name))
40
41 def VisitSubType(self, subtype):
42 # type: (SubTypeDecl) -> None
43 pass
44
45 def VisitProduct(self, product, name, depth):
46 # type: (Product, str, int) -> None
47 pass
48
49
50class ClosureWalk(object):
51 """Analyze how many unique IDs needed for all of syntax.asdl command_t."""
52
53 def __init__(self, type_lookup, seen):
54 # type: (TypeLookup, Dict[str, bool]) -> None
55 self.type_lookup = type_lookup
56 self.seen = seen
57 self.shared = {} # type: Dict[str, bool]
58 self.visited = {} # type: Dict[str, bool]
59
60 def DoModule(self, module, type_name):
61 # type: (ast.Module, str) -> None
62 for d in module.dfns:
63 if isinstance(d, ast.SubTypeDecl):
64 # Don't count these types
65 continue
66
67 elif isinstance(d, ast.TypeDecl):
68 # Only walk for what the user asked for, e.g. the command_t type
69 if d.name == type_name:
70 self.DoType(d.name, d.value)
71 else:
72 raise AssertionError(d)
73
74 def DoType(self, type_name, typ):
75 # type: (str, ast.asdl_type_t) -> None
76 """Given an AST node, add the types it references to seen"""
77 assert typ is not None, typ
78
79 if isinstance(typ, ast.Product):
80 #log('fields %s', ast_node.fields)
81 self.seen[type_name] = True
82 self.DoFields(typ.fields)
83
84 elif isinstance(typ, ast.Sum):
85 for cons in typ.types:
86 # Shared variants will live in a different namespace!
87 if cons.shared_type:
88 self.shared[cons.shared_type] = True
89 continue
90 key = '%s.%s' % (type_name, cons.name)
91 self.seen[key] = True
92 self.DoFields(cons.fields)
93
94 elif isinstance(typ, ast.Use):
95 # Note: we don't 'use core value { value }'? We don't need to walk
96 # that one, because it's really a "cached" value attached to the
97 # AST, not part of the SYNTAX.
98 pass
99 else:
100 raise AssertionError(typ)
101
102 def DoFields(self, field_ast_nodes):
103 # type: (List[ast.Field]) -> None
104 for field in field_ast_nodes:
105 self.DoTypeExpr(field.typ)
106
107 def DoTypeExpr(self, ty_expr):
108 # type: (ast.type_expr_t) -> None
109 """Given an AST node, add the types it references to seen"""
110 if isinstance(ty_expr, ast.NamedType):
111 type_name = ty_expr.name
112
113 if type_name in self.visited:
114 return
115
116 self.visited[type_name] = True
117
118 #typ = self.type_lookup.get(type_name)
119 typ = ty_expr.resolved
120 if typ is None:
121 return
122
123 self.DoType(type_name, typ)
124
125 elif isinstance(ty_expr, ast.ParameterizedType):
126 for child in ty_expr.children:
127 self.DoTypeExpr(child)
128
129 else:
130 raise AssertionError()