| 1 | #!/usr/bin/env python2
|
| 2 | """
|
| 3 | metrics.py
|
| 4 | """
|
| 5 | from __future__ import print_function
|
| 6 |
|
| 7 | from asdl import visitor
|
| 8 | from asdl import ast
|
| 9 |
|
| 10 | # type checking not turned on yet
|
| 11 | from typing import List, Dict, IO, TYPE_CHECKING
|
| 12 | from asdl.ast import SimpleSum
|
| 13 | from asdl.ast import Sum
|
| 14 | from asdl.ast import SubTypeDecl
|
| 15 | from asdl.ast import Product
|
| 16 |
|
| 17 | if TYPE_CHECKING:
|
| 18 | from asdl.front_end import TypeLookup
|
| 19 |
|
| 20 |
|
| 21 | class 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 |
|
| 50 | class 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()
|