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

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