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

146 lines, 89 significant
1"""front_end.py: Lexer and parser for the ASDL schema language."""
2from __future__ import print_function
3
4from asdl import ast
5from asdl.ast import (Module, TypeDecl, SubTypeDecl, Field)
6from asdl import parse
7from asdl.parse import ASDLSyntaxError
8from asdl.util import log
9
10from typing import List, Dict, Tuple, IO, cast, TYPE_CHECKING
11
12if TYPE_CHECKING:
13 TypeLookup = Dict[str, ast.asdl_type_t]
14
15_ = log
16
17_PRIMITIVE_TYPES = [
18 'string',
19 'int',
20 'uint16', # used for Token length - should we generalize this?
21 'BigInt',
22 'float',
23 'bool',
24
25 # 'any' is used for value.{BuiltinProc,BuiltinFunc}, to cast from class
26 # type
27 'any',
28]
29
30
31def _ResolveType(typ, type_lookup):
32 # type: (ast.type_expr_t, TypeLookup) -> None
33 """Recursively attach a 'resolved' field to AST nodes."""
34 if isinstance(typ, ast.NamedType):
35 if typ.name not in _PRIMITIVE_TYPES:
36 ast_node = type_lookup.get(typ.name)
37 if ast_node is None:
38 raise ASDLSyntaxError("Couldn't find type %r" % typ.name)
39 typ.resolved = ast_node
40
41 elif isinstance(typ, ast.ParameterizedType):
42 for child in typ.children:
43 _ResolveType(child, type_lookup)
44
45 if typ.type_name == 'Optional':
46 child = typ.children[0]
47 if isinstance(child, ast.NamedType):
48 if child.name in _PRIMITIVE_TYPES and child.name != 'string':
49 raise ASDLSyntaxError(
50 'Optional primitive type {} not allowed'.format(
51 child.name))
52
53 if child.resolved and isinstance(child.resolved,
54 ast.SimpleSum):
55 raise ASDLSyntaxError(
56 'Optional simple sum type {} not allowed'.format(
57 child.name))
58
59 else:
60 raise AssertionError()
61
62
63def _ResolveFields(field_ast_nodes, type_lookup):
64 # type: (List[Field], TypeLookup) -> None
65 """
66 Args:
67 type_lookup: Populated by name resolution
68 """
69 for field in field_ast_nodes:
70 _ResolveType(field.typ, type_lookup)
71
72
73def _ResolveModule(module, type_lookup):
74 # type: (Module, TypeLookup) -> None
75 """Name resolution for NamedType."""
76
77 # Note: we don't actually load the type, and instead leave that to MyPy /
78 # C++. A consequence of this is TypeNameHeuristic().
79 for u in module.uses:
80 for type_name in u.type_names:
81 type_lookup[type_name] = u
82
83 # NOTE: We need two passes because types can be mutually recursive, e.g.
84 # asdl/arith.asdl.
85
86 # First pass: collect declared types and make entries for them.
87 for ex in module.externs:
88 last = ex.names[-1] # e.g. _Callable
89 if last in type_lookup:
90 raise ASDLSyntaxError('Type %r was already defined' % last)
91 type_lookup[last] = ex
92
93 for d in module.dfns:
94
95 if isinstance(d, SubTypeDecl):
96 if d.name in type_lookup:
97 raise ASDLSyntaxError('Type %r was already defined' % d.name)
98
99 # e.g. CompoundWord < List[str]
100 type_lookup[d.name] = ast.DummyType() # this value isn't used?
101
102 elif isinstance(d, TypeDecl):
103 if d.name in type_lookup:
104 raise ASDLSyntaxError('Type %r was already defined' % d.name)
105
106 # e.g. Token = (str a)
107 type_lookup[d.name] = d.value
108
109 else:
110 raise AssertionError()
111
112 # Second pass: add NamedType.resolved field
113 for d in module.dfns:
114 if isinstance(d, SubTypeDecl): # no fields
115 _ResolveType(d.base_class, type_lookup)
116 continue
117
118 d = cast(ast.TypeDecl, d)
119
120 ast_node = d.value
121 if isinstance(ast_node, ast.Product):
122 #log('fields %s', ast_node.fields)
123 _ResolveFields(ast_node.fields, type_lookup)
124 continue
125
126 if isinstance(ast_node, ast.Sum):
127 for cons in ast_node.types:
128 _ResolveFields(cons.fields, type_lookup)
129 continue
130
131 raise AssertionError(ast_node)
132
133
134def LoadSchema(f, verbose=False):
135 # type: (IO[bytes], bool) -> Tuple[ast.Module, TypeLookup]
136 """Returns an AST for the schema."""
137 p = parse.ASDLParser()
138 schema_ast = p.parse(f)
139 if verbose:
140 import sys
141 schema_ast.Print(sys.stdout, 0)
142
143 # Make sure all the names are valid
144 type_lookup = {} # type: TypeLookup
145 _ResolveModule(schema_ast, type_lookup)
146 return schema_ast, type_lookup