o
    6d9                    @   s  d dl mZmZmZmZ d dlmZ d dlZd dlZd dl	Z	dZ
e
r&d dlZd dlZeedZddlmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZA dd	lBmCZC dd
lDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZMmNZNmOZOmPZPmQZQmRZR dd ZSdddZTdd ZU	dddZVeWdZXeWdZYee0e1e3e4dZZG dd de[Z\G dd de]Z^dS )    )absolute_importdivisionprint_functionunicode_literals)defaultdictNFre   )1AliasAnnotationTypeAnnotationTypeParamApiApiNamespaceApiRouteApiRoutesByVersionBooleanBytesCustomAnnotationDataType
DeprecatedDeprecationInfoFloat32Float64Int32Int64is_aliasis_composite_typeis_field_typeis_list_typeis_map_typeis_nullable_typeis_primitive_typeis_struct_typeis_user_defined_typeis_union_typeis_void_typeListMapNullableOmittedPreviewParameterErrorRedactedBlotRedactedHashStringStructStructFieldTagRef	TimestampUInt32UInt64Union
UnionFieldUserDefinedVoidunwrap_aliasesunwrap_nullable   )InvalidSpec)AstAliasAstAnnotationDefAstAnnotationTypeDef	AstImportAstNamespaceAstRouteDefAstStructDefAstStructPatch	AstTagRef
AstTypeDef
AstTypeRefAstUnionDefAstUnionPatchAstVoidFieldc                 C   s0   |  dd dd dd sJ dd|  S )N_ ./z,Only use quote() with names or IDs in Stone.z'%s')replaceisalnums rR   rC:\Users\jesus\OneDrive\Desktop\erpjis_fastapi\backend\jisbackend\Lib\site-packages\stone/frontend/ir_generator.pyquote[   s   "rT   c              	   C   s   g }t | |||d\}}|D ]}|| q| D ])\}}	z| j| }
|	D ]}|
|D ]}|| q-q&W q tyC   |sA Y qw |S )a5  
    Given a documentation string, parse it and return all references to other
    data types. If there are references to routes, include also the data types of
    those routes.

    Args:
    - api: The API containing this doc ref.
    - doc: The documentation string to parse.
    - namespace_context: The namespace name relative to this documentation.
    - ignore_missing_entries: If set, this will skip references to nonexistent data types instead
                              of raising an exception.

    Returns:
    - a list of referenced data types
    )ignore_missing_entries)(parse_data_types_and_routes_from_doc_refappenditems
namespaces!get_route_io_data_types_for_routeKeyError)apidocnamespace_contextrU   output
data_typesroutes_by_nsdZns_nameroutesnsrrR   rR   rS   parse_data_types_from_doc_ref`   s(   

rf   c                 C   sX   d| v r$|  dd\}}z	t|}W ||fS  ty#   td| w | }d}||fS )z
    Parse a route representation string and return the route name and version number.

    :param route_repr: Route representation string.

    :return: A tuple containing route name and version number.
    :r:   z Invalid route representation: {})splitint
ValueErrorformat)
route_repr
route_nameversionrR   rR   rS   parse_route_name_and_version   s   
ro   c                 C   s~  |dusJ t  }tt }t|D ]}z|d}|d}| j| }	|dkrAd|v r?|dd\}
}|	j|
 }|| nn	 nl|dkrd|v rW|dd\}}| j| }n|	}zt	|\}}W n t
ys } ztt|d}~ww |j| j| }||j | n(|dkrd|v r|dd\}}| j| j| }|| n
|	j| }|| W q ty   |s Y qw ||fS )	a  
    Given a documentation string, parse it and return all references to other
    data types and routes.

    Args:
    - api: The API containing this doc ref.
    - doc: The documentation string to parse.
    - namespace_context: The namespace name relative to this documentation.
    - ignore_missing_entries: If set, this will skip references to nonexistent data types instead
                              of raising an exception.

    Returns:
    - a tuple of referenced data types and routes
    NtagvalfieldrL   r:   routetype)setr   
doc_ref_refinditergrouprY   rh   data_type_by_nameaddro   rj   r[   strroutes_by_name
at_versionname)r\   r]   r^   rU   r`   rc   matchrp   rq   Zsupplied_namespace	type_name__Zdoc_typenamespace_name	namespacerm   rn   exrs   rR   rR   rS   rV      sR   





rV   z:(?P<tag>[A-z]+):`(?P<val>.*?)`z4^(null|true|false|-?\d+(\.\d*)?(e-?\d+)?|"[^\\"]*")$)r   r(   r)   r+   r,   c                   @   s   e Zd ZdZdS )EnvironmentN)__name__
__module____qualname__r   rR   rR   rR   rS   r      s    r   c                   @   s  e Zd Zeeeeeee	e
eeeeegZedYi dd eD ZdZddZdd Zd	d
 Zdd Zd[ddZedd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Z dd  Z!d!d" Z"d#d$ Z#d%d& Z$d'd( Z%d)d* Z&d+d, Z'd-d. Z(d/d0 Z)d1d2 Z*d3d4 Z+d5d6 Z,d7d8 Z-d[d9d:Z.d;d< Z/d=d> Z0d?d@ Z1dAdB Z2dCdD Z3dEdF Z4dGdH Z5d\dIdJZ6dKdL Z7dMdN Z8dOdP Z9dQdR Z:dSdT Z;dUdV Z<	d\dWdXZ=dS )]IRGeneratorc                 C      i | ]}|j |qS rR   )r   ).0	data_typerR   rR   rS   
<dictcomp>       zIRGenerator.<dictcomp>FNc                 C   sH   || _ || _td| _t|d| _i | _t | _	i | _
i | _|| _dS )a  Creates a new tower of stone.

        :type specs: List[Tuple[path: str, text: str]]
        :param specs: `path` is never accessed and is only used to report the
            location of a bad spec to the user. `spec` is the text contents of
            a spec (.stone) file.
        z	stone.idl)rn   N)_partial_asts_debuglogging	getLogger_loggerr   r\   _env_by_namespaceru   _resolution_in_progress_item_by_canonical_name_patch_data_by_canonical_name_routes)selfZpartial_astsrn   debugZroute_whitelist_filterrR   rR   rS   __init__   s   	
zIRGenerator.__init__c                 C   s   g }| j D ]3}| |}| j|j}| |j|j}|| j|< |jdur+||j |	||f | 
|| q| | |   |   |   |   |   |   |   |   |   | jdurk|   | j  | jS )z}Parses the text of each spec and returns an API description. Returns
        None if an error was encountered during parsing.N)r   _extract_namespace_ast_noder\   ensure_namespacer~   _get_base_namer   r]   Zadd_docrW   !_add_data_types_and_routes_to_api_add_imports_to_env_merge_patches_populate_type_attributes_populate_field_defaults_populate_enumerated_subtypes_populate_route_attributes&_populate_recursive_custom_annotations_populate_examples_validate_doc_refs_validate_annotationsr   %_filter_namespaces_by_route_whitelist	normalize)r   raw_apiZpartial_astZnamespace_ast_noder   	base_namerR   rR   rS   generate_IR  s0   






zIRGenerator.generate_IRc                 C   s   t |dkst|d ts#| jr| jd| td|d j|d j|dd D ]}t|tr<td|d j|d jq)|	dS )ab  
        Checks that the namespace is declared first in the spec, and that only
        one namespace is declared.

        Args:
            desc (List[stone.stone.parser.ASTNode]): All AST nodes in a spec
                file in the order they were defined.

        Return:
            stone.frontend.ast.AstNamespace: The namespace AST node.
        r   zDescription: %rzVFirst declaration in a stone must be a namespace. Possibly caused by preceding errors.r:   Nz(Only one namespace declaration per file.)
len
isinstancer@   r   r   infor;   linenopathpop)r   descitemrR   rR   rS   r   8  s   

z'IRGenerator._extract_namespace_ast_nodec                 C   s\  |  |j}|D ]}t|tr"| ||}|| | ||j qt|ts,t|tr<| 	|j|j}||f| j
|< qt|trV| ||}|| | j||jdd qt|tr\qt|trt| ||}|| | ||j qt|tr| ||}	||	 | ||j qt|tr| ||}
||
 | ||j qtd|jj dS )a  
        From the raw output of the parser, create forward references for each
        user-defined type (struct, union, route, and alias).

        Args:
            namespace (stone.api.Namespace): Namespace for definitions.
            desc (List[stone.stone.parser._Element]): All AST nodes in a spec
                file in the order they were defined. Should not include a
                namespace declaration.
        T)allow_duplicatezUnknown AST node type %rN)_get_or_create_envr~   r   rE   _create_typeZadd_data_type_check_canonical_name_availablerC   rH   r   r   rA   _create_route	add_router?   r<   _create_alias	add_aliasr=   _create_annotationZadd_annotationr>   _create_annotation_typeZadd_annotation_typeAssertionError	__class__r   )r   r   r   envr   api_typer   rs   alias
annotationannotation_typerR   rR   rS   r   P  s>   










z-IRGenerator._add_data_types_and_routes_to_apic                 C   s   |  |j|}|| jvr|| j|< d S | j| }|j|jk}|r"|s>d| ||j| ||j|j|jf }t||j|jd S )Nz7Name of %s '%s' conflicts with name of %s '%s' (%s:%s).)r   r~   r   r   &_get_user_friendly_item_type_as_stringr   r   r;   )r   r   r   r   r   Zstored_itemZis_conflict_between_same_typemsgrR   rR   rS   r     s    

z+IRGenerator._check_canonical_name_availablec                 C   sR   t |trdS t |trdS t |trdS t |trdS t |tr#dS td| )Nzuser-defined typers   r   r   zannotation typezunhandled type %r)r   rE   rA   r<   r@   r>   r   )clsr   rR   rR   rS   r     s   




z2IRGenerator._get_user_friendly_item_type_as_stringc                 C   s(   | dd dd | dd  S )NrJ   rK   rM   )rN   lower)r   Z	input_strr   rR   rR   rS   r     s   zIRGenerator._get_base_namec                 C   s   |D ]X\}}|D ]Q}t |trY|j|jkrtd|j|j|j| jjvr1tdt	|j |j|j| 
|j}| 
|j}|j|v rTtdt	|jt	|jf |j|j|||j< qqdS )aH  
        Scans raw parser output for import declarations. Checks if the imports
        are valid, and then creates a reference to the namespace in the
        environment.

        Args:
            raw_api (Tuple[Namespace, List[stone.stone.parser._Element]]):
                Namespace paired with raw parser output.
        z Cannot import current namespace.z(Namespace %s is not defined in any spec.z1Circular import of namespaces %s and %s detected.N)r   r?   r~   targetr;   r   r   r\   rY   rT   r   )r   r   r   r   r   r   Zimported_envrR   rR   rS   r     s6   



zIRGenerator._add_imports_to_envc                 C   sf   |j |v r||j  }tdt|j |jj|jjf |j|j| j|j}t	|j ||}|||j < |S )N"Symbol %s already defined (%s:%d).)
r~   r;   rT   	_ast_noder   r   r\   r   r   r	   )r   r   r   existing_dtr   r   rR   rR   rS   r     s   


zIRGenerator._create_aliasc                 C   s   |j |v r||j  }tdt|j |jj|jjf |j|j| j|j}|j	r3|j
r3td|j|j|jd u rS|jtv rSt|j }||j ||g|j	R i |j
}n |jd urd|j| j|jdd t|j |||j|j|j	|j
}|||j < |S )Nr   zCAnnotations accept either positional or keyword arguments, not bothTZimported_annotation_type)r~   r;   rT   r   r   r   r\   r   r   argskwargsannotation_type_nsr   "BUILTIN_ANNOTATION_CLASS_BY_STRINGadd_imported_namespacer   )r   r   r   r   r   Zannotation_classr   rR   rR   rS   r     s>   




"


zIRGenerator._create_annotationc              
   C   sb  |j |v r||j  }tdt|j |jj|jjf |j|j| j|j}|j t	v r8tdt|j f |j|jg }|j
D ]c}|jrJtd|j|j| ||jd}t|\}}	t|trktdt|j |j|j|	r~|jr~tdt|j |j|jt|stdt|j |j|j|t|j ||j|j|j| q=t|j ||j|}
|
||j < |
S )Nr   z,Cannot redefine built-in annotation type %s.z?Annotations cannot be applied to parameters of annotation typesTzParameter {} cannot be Void.zDParameter {} cannot be a nullable type and have a default specified.z<Parameter {} must have a primitive type (possibly nullable).)r~   r;   rT   r   r   r   r\   r   r   r   paramsannotations_resolve_typetype_refr9   r   r7   rk   has_defaultr    rW   r   r]   defaultr
   )r   r   r   r   r   r   paramZ
param_typedtZnullable_dtr   rR   rR   rS   r     sb   








z#IRGenerator._create_annotation_typec              
   C   s   |j |v r||j  }tdt|j |jj|jjf |j|j| j|j}t	|t
rSz
t|j ||d}W n6 tyR } ztdt|j |jd f |j|jd}~ww t	|trct|j |||jd}ntdt| |||j < |S )z1Create a forward reference for a union or struct.r   )r~   r   ast_nodezBad declaration of %s: %sr   N)r~   r   r   closedzUnknown type definition %r)r~   r;   rT   r   r   r   r\   r   r   r   rB   r.   r*   r   rG   r4   r   r   rt   )r   r   r   r   r   r   erR   rR   rS   r   *  s>   





zIRGenerator._create_typec                 C   s   | j  D ]N\}}| |j|j}|| jvr$tdt|j|j|j	| j| }| 
|| t|ttfrK| || | j|j7  _| || qtd|jjdS )z>Injects object patches into their original object definitions.z5Patch {} must correspond to a pre-existing data_type.Unknown Patch Object Type {}N)r   valuesr   r~   r   r;   rk   rT   r   r   _check_patch_type_mismatchr   rC   rH   _check_field_names_uniquefields_inject_patched_examplesr   r   r   )r   patched_itemZpatched_namespaceZpatched_item_base_nameexisting_itemrR   rR   rS   r   E  s$   

zIRGenerator._merge_patchesc                 C   s   dd }t |trt |ts|||d dS dS t |tr?t |ts*|||d dS |j|jkr=||||jr8dnd dS dS td|jj	)zHEnforces that each patch has a corresponding, already-defined data type.c              	   S   s6   d}t |t| jt|j|j|jt|| j| j)NzeType mismatch. Patch {} corresponds to pre-existing data_type {} ({}:{}) that has type other than {}.)r;   rk   rT   r~   r   r   )r   r   Zdata_type_name	error_msgrR   rR   rS   raise_mismatch_error[  s   zDIRGenerator._check_patch_type_mismatch.<locals>.raise_mismatch_errorstructunionZunion_closedr   N)
r   rC   rB   rH   rG   r   r   rk   r   r   )r   r   r   r   rR   rR   rS   r   Y  s"   




z&IRGenerator._check_patch_type_mismatchc                 C   sd   dd |j D }|j D ]$}|j| v r/||j }tdt|jt|j|j|j|j|jqdS )z1Enforces that patched fields don't already exist.c                 S   r   rR   r~   )r   frR   rR   rS   r   v  r   z9IRGenerator._check_field_names_unique.<locals>.<dictcomp>z<Patched field {} overrides pre-existing field in {} ({}:{}).N)r   r~   keysr;   rk   rT   r   r   )r   r   r   Zexisting_fields_by_nameZpatched_fieldZexisting_fieldrR   rR   rS   r   t  s   


z%IRGenerator._check_field_names_uniquec                 C   sb   |j  D ])\}}|j | }|j }||v r|| j|j qd}t|t|j|j|j	dS )z0Injects patched examples into original examples.zFExample defined in patch {} must correspond to a pre-existing example.N)
examplesrX   r   updater;   rk   rT   r~   r   r   )r   r   r   keyrJ   Zpatched_exampleZexisting_examplesr   rR   rR   rS   r     s   
z$IRGenerator._inject_patched_examplesc           	         s  j j D ]}|j |jD ]l}t|tr}|jj	|jj
f}|jrM|j vr5tdt|j g|R   |j }t|tsLtdt|j g|R  n }|j|vratdt|j g|R  ||j }t|tsxtdt|j g|R  || q|jD ]#} |jj}||jj|  fdd|jjD }|| q|jD ]2}|jsqj| t|tr | nt|tr̈ | ntdt | j!| qqt"jdksJ d	S )
zo
        Converts each struct, union, and route from a forward reference to a
        full definition.
        Namespace %s is not imported%s is not a namespace.z!Annotation type %s does not existz%s is not an annotation typec                       g | ]}  |qS rR   _resolve_annotation_typer   r   r   r   rR   rS   
<listcomp>      z9IRGenerator._populate_type_attributes.<locals>.<listcomp>zUnhandled type: %rr   N)#r\   rY   r   r   r~   r   r   r   r   r   r   r   r;   rT   r   Zannotation_type_namer
   set_attributesaliasesr   r   r]   set_annotationsr`   _is_forward_refr   rz   r.    _populate_struct_type_attributesr4   _populate_union_type_attributesr   rt   remover   )	r   r   r   locZannotation_type_envr   r   r   r   rR   r   rS   r     s~   












z%IRGenerator._populate_type_attributesc                 C   s   d}|j j}|rA| ||d}t|trtd|j j|j jt|tr-td|j j|j jt|t	sAtdt
|j |j j|j jg }|j jD ]}| ||}|| qG||j j|| dS )zV
        Converts a forward reference of a struct into a complete definition.
        NTz@A struct cannot extend an alias. Use the canonical name instead.z'A struct cannot extend a nullable type.z<A struct can only extend another struct: %s is not a struct.)r   extendsr   r   r	   r;   r   r   r'   r.   rT   r~   r   _create_struct_fieldrW   r   r]   )r   r   r   parent_typer  api_type_fieldsstone_fieldapi_type_fieldrR   rR   rS   r     s8   



z,IRGenerator._populate_struct_type_attributesc                 C   s2  d}|j j}|rA| ||d}t|trtd|j j|j jt|tr-td|j j|j jt|t	sAtdt
|j |j j|j jg }|j jD ]}|jdkrVtd|j|j|| || qGd}|jrx|rw|jswtd|j |j j|j jn|r}|jrtdt d|j dd	}|| ||j j||| dS )
zU
        Converts a forward reference of a union into a complete definition.
        NTz?A union cannot extend an alias. Use the canonical name instead.z&A union cannot extend a nullable type.z9A union can only extend another union: %s is not a union.otherzcUnion cannot define an 'other' field because it is reserved as the catch-all field for open unions.z6Union cannot be closed since parent type '%s' is open.)r~   r   r]   r   Z	catch_all)r   r  r   r   r	   r;   r   r   r'   r4   rT   r~   r   rW   _create_union_fieldr   r5   r7   r   r]   )r   r   r   r  r  r  r  Zcatch_all_fieldrR   rR   rS   r    s`   






z+IRGenerator._populate_union_type_attributesc                    s   t    fdd| jj D ]U}t  }|jD ]	}|| q|jD ]	}|| q%|jD ]}||j ||j	 ||j
 q2|D ]\}}|jjj|jkrd|j|jjdd qOqdS )z
        Populates custom annotations applied to fields recursively. This is done in
        a separate pass because it requires all fields and routes to be defined so that
        recursive chains can be followed accurately.
        c                    s  t  st S  jd ur jS  v rt S   t }t s&t rB jD ]|j |fddj	D  q)n@t
 r\| j | fdd j	D  n&t ri| j nt rv| j nt r| j | _|S )Nc                       g | ]} |fqS rR   rR   r   )rr   rR   rS   r   D      zWIRGenerator._populate_recursive_custom_annotations.<locals>.recurse.<locals>.<listcomp>c                    r  rR   rR   r   )r   rR   rS   r   I  r  )r   ru   Zrecursive_custom_annotationsrz   r!   r#   r   r   r   Zcustom_annotationsr   r   r   value_data_typer   )r   r   Zdata_types_seenrecurse)r   rr   rS   r  /  s8   




zCIRGenerator._populate_recursive_custom_annotations.<locals>.recurseTr   N)ru   r\   rY   r   r`   r   r   rc   arg_data_typeresult_data_typeerror_data_typer   r   r~   r   )r   r   Znamespace_annotationsr   r   rs   rJ   r   rR   r  rS   r   '  s*   '


z2IRGenerator._populate_recursive_custom_annotationsc                 C   s   | j j D ]m}|jD ]g}t|tsq|jD ][}|jjsqt|jj	t
r.t|j|jj	j}n|jj	}|jjjr;|du slz|jjdv rFt|}|j| W n tyk } ztdt|jj|f |jj|jjd}~ww || qqqdS )z
        Populate the defaults of each field. This is done in a separate pass
        because defaults that specify a union tag require the union to have
        been defined.
        N)r   r   z#Field %s has an invalid default: %s)r\   rY   r   r`   r   r.   r   r   r   r   rD   r0   r   rp   r   nullabler~   floatcheckrj   r;   rT   r   r   set_default)r   r   r   rr   default_valuer   rR   rR   rS   r   l  s<   


z$IRGenerator._populate_field_defaultsc                 C   sP   |   }| j| | jj D ]}| |j}|jD ]	}| ||| qqdS )zV
        Converts all routes from forward references to complete definitions.
        N)	_validate_stone_cfgr\   Zadd_route_schemarY   r   r   r~   rc   !_populate_route_attributes_helper)r   Zroute_schemar   r   rs   rR   rR   rS   r     s   
z&IRGenerator._populate_route_attributesc              
   C   s  |  ||jj}|  ||jj}|  ||jj}|jj}|r|d s$J |d }|d }	|r~|	s2J d}
d}||v rNt|| trK|	|| jvrJd}
nd}nd}
|
rbt	dt
||	f |jj|jj|rrt	dt
| |jj|jj|| j|	 }t|}nt }nd}i }|jjD ]}|||j< qz||}W n ty } zt	d	|jd  |jj|jjd}~ww |j||jj||||d
 dS )z\
        Converts a single forward reference of a route into a complete definition.
        r   r:   r   FTz!Undefined route %s at version %d.z%s must be a route.Nz$Route does not define attr key '%s'.)
deprecatedr]   r  r  r  attrs)r   r   Zarg_type_refZresult_type_refZerror_type_refr  r   r   r}   r;   rT   r   r   r   r  r~   Zcheck_attr_reprr[   r   r   r]   )r   r   rs   ZschemaZarg_dtZ	result_dtZerror_dtZast_deprecatedZnew_route_nameZnew_route_versionZis_not_definedZis_not_routeZ	new_router  Zattr_by_nameattrZvalidated_attrsr   rR   rR   rS   r    sn   


z-IRGenerator._populate_route_attributes_helperc                    s   t |trtdt|j |j|j |j} fdd|j	D }t |t
r6tdt|j |j|jt |trK|jrKtdt|j |j|jt|j||j|d}|| |S )a  
        This function resolves symbols to objects that we've instantiated in
        the current environment. For example, a field with data type named
        "String" is pointed to a String() object.

        The caller needs to ensure that this stone_field is for a Struct and not
        for a Union.

        Returns:
            stone.data_type.StructField: A field of a struct.
        z(Struct field %s cannot have a Void type.c                    r   rR   r   r   r   rR   rS   r     r   z4IRGenerator._create_struct_field.<locals>.<listcomp>z@Field %s cannot be a nullable type and have a default specified.r~   r   r]   r   )r   rI   r;   rT   r~   r   r   r   r   r   r7   r'   r   r/   r]   r   )r   r   r  r   r   r	  rR   r   rS   r    s@   


z IRGenerator._create_struct_fieldc                    s    fdd|j D }t|trt|jt |j|d}n# |j}t|tr5t	dt
|j |j|jt|j||j|d}|| |S )a  
        This function resolves symbols to objects that we've instantiated in
        the current environment. For example, a field with data type named
        "String" is pointed to a String() object.

        The caller needs to ensure that this stone_field is for a Union and not
        for a Struct.

        Returns:
            stone.data_type.UnionField: A field of a union.
        c                    r   rR   r   r   r   rR   rS   r     r   z3IRGenerator._create_union_field.<locals>.<listcomp>r  zBUnion member %s cannot have Void type explicit, omit Void instead.)r   r   rI   r5   r~   r7   r]   r   r   r;   rT   r   r   r   )r   r   r  r   r	  r   rR   r   rS   r    s*   


zIRGenerator._create_union_fieldc              
   C   s  t |tsJ d| t|j}|jd t|j}t|jp!d}|\}}|| t|krEt	dt
|jt| t
|jf g|R  || t|k rZt	dt
|j g|R  i }	t|jD ]\}
}|
|| k|	|< qa|D ]*}||	vrt	dt
|t
|jf g|R  |	| st	dt
| g|R  |	|= qpz||i |W S  ty } zt	dt
|j|jd	 f g|R  d
}~ww )a  
        Responsible for instantiating a data type with additional attributes.
        This method ensures that the specified attributes are valid.

        Args:
            data_type_class (DataType): The class to instantiate.
            data_type_attrs (dict): A map from str -> values of attributes.
                These will be passed into the constructor of data_type_class
                as keyword arguments.

        Returns:
            stone.data_type.DataType: A parameterized instance.
        z)Expected stone.data_type.DataType, got %rr   rR   z*Missing positional argument %s for %s typez)Too many positional arguments for %s typezUnknown argument %s to %s type.zAPositional argument %s cannot be specified as a keyword argument.zBad argument to %s type: %sr   N)
issubclassr   inspect
getargspecr   r   r  r   defaultsr;   rT   r   	enumerater*   )r   Zdata_type_classZdata_type_argsr  Zargspecnum_argsnum_defaultspos_argskw_argsr   ir   r   rR   rR   rS   _instantiate_data_type$  sn   
z"IRGenerator._instantiate_data_typec                 C   sR  |j |jf}|j}|jr5|j|vrtdt|j g|R  ||j }t|ts5tdt|j g|R  |j|vrGtdt|j g|R  ||j }|t	u r[|j
r[tdg|R  t|rs| ||j}| |||j |jf}n)t|trtdg|R  |jd s|jd rtdt|j g|R  ||j }|jr| j|}	t|tr|	j| j|jd	d
 nt|tr|	j| j|jd	d |rt|tr|jr|| jv rtdt|j g|R  | j| t|tr| || nt|tr| || | j| |j
r't|\}
}t|
tr#tdg|R  t|}|S )z
        Resolves the data type referenced by type_ref.

        If `enforce_fully_defined` is True, then the referenced type must be
        fully populated (fields, parent_type, ...), and not simply a forward
        reference.
        r   r   zSymbol %s is undefined.zVoid cannot be marked nullable.z"A route cannot be referenced here.r   r:   z8Attributes cannot be specified for instantiated type %s.T)Zimported_data_type)Zimported_aliasz,Unresolvable circular reference for type %s.z3Cannot mark reference to nullable type as nullable.) r   r   r   rd   r;   rT   r   r   r~   r7   r  r   isclass_resolve_argsr   r)  r   r\   r   r6   r   r	   r   r   rz   r.   r   r4   r  r  r8   r'   )r   r   r   Zenforce_fully_definedr  Zorig_namespace_nameobjZresolved_data_type_argsr   r   Zunwrapped_dtrJ   rR   rR   rS   r   g  s   











zIRGenerator._resolve_typec                 C   s   |j |jf}|jr2|j|vrtdt|j g|R  ||j }t|ts2tdt|j g|R  |j|vrDtdt|j g|R  ||j S )zL
        Resolves the annotation type referenced by annotation_ref.
        r   r   zAnnotation %s does not exist.)r   r   rd   r;   rT   r   r   r   )r   r   Zannotation_refr  rR   rR   rS   r     s,   




z$IRGenerator._resolve_annotation_typec                    sF   |\}}fdd  fdd|D } fdd|  D }||fS )zk
        Resolves type references in data type arguments to data types in
        the environment.
        c                    s   t | tr | S | S N)r   rF   r   )vr   rR   rS   check_value  s   
z.IRGenerator._resolve_args.<locals>.check_valuec                    s   g | ]} |qS rR   rR   )r   Zpos_argr/  rR   rS   r     r   z-IRGenerator._resolve_args.<locals>.<listcomp>c                    s   i | ]	\}}| |qS rR   rR   )r   kr.  r0  rR   rS   r     s    z-IRGenerator._resolve_args.<locals>.<dictcomp>)rX   )r   r   r   r&  r'  Znew_pos_argsZnew_kw_argsrR   )r/  r   r   rS   r+    s
   zIRGenerator._resolve_argsc                 C   s   |j |v rOt||j  tr6|j||j  jv r5||j  j|j }tdt|j |j|jj|jj	f |j	|jn||j  }tdt|j |jj|jj	f |j	|jt ||j < t
|j |j|d}|||j  j|j< |S )a  
        Constructs a route and adds it to the environment.

        Args:
            env (dict): The environment of defined symbols. A new key is added
                corresponding to the name of this new route.
            item (AstRouteDef): Raw route definition from the parser.

        Returns:
            stone.api.ApiRoutesByVersion: A group of fully-defined routes indexed by versions.
        z/Route %s at version %d already defined (%s:%d).r   )r~   rn   r   )r~   r   r   rn   r}   r;   rT   r   r   r   r   )r   r   r   r   rs   rR   rR   rS   r     s8   

zIRGenerator._create_routec                 C   s8   || j v r| j | }|S t| j}||_|| j |< |S r-  )r   copydefault_envr   )r   r   r   rR   rR   rS   r     s   


zIRGenerator._get_or_create_envc                 C   sT  | j j D ]}| |j}|jD ]a}t|tr|jj	sqg }|jj	d D ]B}|j
j}|j
j}|j
j}|j
j|vrCtdt| ||| ||j
d}	t|	tsZtdt| ||t|j|	d |}
||
 q%|||jj	d  q|jD ]0}t|tr| sqv| D ]}|j st|jj	dkrtd|jj |jjj|jjjqqvqd S )Nr   zUndefined type %s.Tz'Enumerated subtype %s must be a struct.r:   z Subtype '%s' cannot be extended.)r\   rY   r   r   r~   r`   r   r.   r   subtypesr   r   r   r;   rT   r   r5   rW   Zset_enumerated_subtypeshas_enumerated_subtypesget_enumerated_subtypesr   r   )r   r   r   r   Zsubtype_fieldsZsubtype_fieldZsubtype_namer   r   subtyper   rR   rR   rS   r     sj   








z)IRGenerator._populate_enumerated_subtypesc                 C   sd   | j j D ]}|jD ]}|jj D ]}|| qqq| j j D ]}|jD ]}|  q(q#dS )aW  Construct every possible example for every type.

        This is done in two passes. The first pass assigns examples to their
        associated types, but does not resolve references between examples for
        different types. This is because the referenced examples may not yet
        exist. The second pass resolves references.
        N)r\   rY   r   r`   r   r   Z_add_exampleZ_compute_examples)r   r   r   ZexamplerR   rR   rS   r   @  s   


zIRGenerator._populate_examplesc              	   C   s   | j j D ]U}| |j}|jD ]0}|jr'| ||j|jj	d |jj
f| |jD ]}|jr@| ||j|jj	d |jj
f| q*q|jD ]}|jrZ| ||j|jj	d |jj
f qEqdS )z
        Validates that all the documentation references across every docstring
        in every spec are formatted properly, have valid values, and make
        references to valid symbols.
        r:   N)r\   rY   r   r   r~   r`   r]   _validate_doc_refs_helperr   r   r   r   rc   )r   r   r   r   rr   rs   rR   rR   rS   r   Q  s<   


zIRGenerator._validate_doc_refsc                    sX  t |D ]}|d}|d|dkrdv rdd\} ||vr4td t|f g|R  t|| trKtdt t|f g|R  t|| trbdd\}} || | }	nt|| t	ro|| j
}	n|| }	t fd	d
|	jD stdt g|R  q|dusJ tfdd
|jD stdt g|R  q|dkrdd  k rtd k sn tdt g|R  q|dkr8dv rdd\}||vrtd| g|R  || }
n|}
t\}}||
vrtdt|g|R  t|
| ts!tdt|g|R  ||
| jvr7tdt||g|R  q|dkrdv r^dd\}||vrYtd| g|R  || }
n|}
|
vrotd g|R  t|
 ttfstdt g|R  q|dkrtstdt g|R  qtdt| g|R  dS )a  
        Validates that all the documentation references in a docstring are
        formatted properly, have valid values, and make references to valid
        symbols.

        Args:
            env (dict): The environment of defined symbols.
            doc (str): The docstring to validate.
            lineno (int): The line number the docstring begins on in the spec.
            type_context (stone.data_type.UserDefined): If the docstring
                belongs to a user-defined type (Struct or Union) or one of its
                fields, set this to the type. This is needed for "field" doc
                refs that don't name a type to be validated.
        rp   rq   rr   rL   r:   z1Bad doc reference to field %s of unknown type %s.z*Bad doc reference to field %s of route %s.r   c                 3       | ]}|j  kV  qd S r-  r   r   rr   )
field_namerR   rS   	<genexpr>      z8IRGenerator._validate_doc_refs_helper.<locals>.<genexpr>z&Bad doc reference to unknown field %s.Nc                 3   r9  r-  r   r:  )rq   rR   rS   r<    r=  link zJBad doc reference to link (need a title and uri separated by a space): %s.rs   z(Unknown doc reference to namespace '%s'.z"Unknown doc reference to route {}.z(Doc reference to type {} is not a route.z3Doc reference to route {} has undefined version {}.rt   z#Unknown doc reference to type '%s'.z2Doc reference to type %s is not a struct or union.zBad doc reference value %s.zUnknown doc reference tag %s.)rv   rw   rx   rh   r;   rT   r   r   r   r	   r   any
all_fieldsrfindr   ro   rk   r}   r.   r4   doc_ref_val_rer   )r   r   r]   r  type_contextr   rp   r   r   Zdata_type_to_checkZenv_to_checkrm   rn   rR   )r;  rq   rS   r8  o  s  



$










z%IRGenerator._validate_doc_refs_helperc                 C   sZ   | j j D ]$}|jD ]}|jD ]
}|jr| | qq|jD ]
}|jr)| | qqdS )a  
        Validates that all annotations are attached to proper types and that no field
        has conflicting inherited or direct annotations. We need to go through all reference
        chains to make sure we don't override a redactor set on a parent alias or type
        N)	r\   rY   r   r`   r   redactor+_validate_field_can_be_tagged_with_redactorr   ,_validate_object_can_be_tagged_with_redactor)r   r   r   rr   r   rR   rR   rS   r     s   




z!IRGenerator._validate_annotationsc                 C   s,   t |jrtd|jj|jj| | dS )z~
        Validates that the field type can be annotated and that alias does not have
        conflicting annotations.
        zLRedactors can only be applied to alias definitions, not to alias references.N)r   r   r;   r   r   r   rG  )r   rr   rR   rR   rS   rF    s   
z7IRGenerator._validate_field_can_be_tagged_with_redactorc                 C   s  |j }|j}|jj|jjf}|}t|tst|tr@t|dr3|j	r3t
dt|t|jf g|R  |j }t|tst|tst|dr~|j	rt|sPt|rn	 t|rY|j}n|j }t|pgt|pgt|}|du rmnqQt|svt|rt
dg|R  dS dS dS )z{
        Validates that the object type can be annotated and object does not have
        conflicting annotations.
        rE  z5A redactor has already been defined for '%s' by '%s'.TFz9Redactors can't be applied to user-defined or void types.N)r   r~   r   r   r   r   r	   r'   hasattrrE  r;   r{   r   r   r  r   r"   r$   )r   Zannotated_objectr   r~   r  Zcurr_data_typeZshould_continuerR   rR   rS   rG    s:   z8IRGenerator._validate_object_can_be_tagged_with_redactorc                 C   s   dd }z	| j jd}W n ty   |  Y S w |jr,|jd }td|jj|jj|j	s2| S |j	D ]}|j
dkrFtd|jj|jjq5|S )zN
        Returns:
             Struct: A schema for route attributes.
        c                  S   s"   t dtdd } | d g d  | S )NRoute	stone_cfg)r.   r   r   rP   rR   rR   rS   mk_route_schema&  s   z8IRGenerator._validate_stone_cfg.<locals>.mk_route_schemarJ  r   z4No routes can be defined in the stone_cfg namespace.rI  zFOnly a struct named 'Route' can be defined in the stone_cfg namespace.)r\   rY   r   r[   rc   r;   r   r   r   r`   r~   )r   rK  rJ  rs   r   rR   rR   rS   r  !  s0   




zIRGenerator._validate_stone_cfgc                 C   s6  | j dus	J dd| j v sJ d| j v sJ i }| j d  D ]<\}}g }|dgkr:| jj| }dd |jD }n|D ]}t|\}}|dkrR|d	|| q<|| q<|||< q g }	| D ]l\}}|| jjvrstd
| | jj| }|j	dur|	
t| j|j	| d|vsJ |D ]=}
t|
\}}||jvs||j| jvrtd||f |j| j| }|	
|| |j	dur|	
t| j|j	| qqc| j d  D ]I\}}|| jjvrtd
| | jj| }|j	dur|	
t| j|j	| |D ] }|| jj| jvrtd| | jj| j| }|	| qq| |	\}}| jj D ]j}tt||j }||_dd |D |_dd ||j D }|j|v rb||j }tt|| }n|}g }|D ]}t|\}}|j| j| }|| qhg |_i |_i |_|  |D ]}|| qq.dS )z
        Given a parsed API in IR form, filter the user-defined datatypes
        so that they include only the route datatypes and their direct dependencies.
        NzMissing route whitelistroute_whitelistZdatatype_whitelist*c                 S      g | ]}|  qS rR   Zname_with_version)r   rs   rR   rR   rS   r   W  r   zEIRGenerator._filter_namespaces_by_route_whitelist.<locals>.<listcomp>r:   z{}:{}zNamespace %s is not defined!z&Route %s at version %d is not defined!zDatatype %s is not defined!c                 S   r   rR   r   )r   rb   rR   rR   rS   r     r   zEIRGenerator._filter_namespaces_by_route_whitelist.<locals>.<dictcomp>c                 S   rN  rR   rO  )r   Zoutput_routerR   rR   rS   r     r  )r   rX   r\   rY   rc   ro   rW   rk   r   r]   extendrf   r|   r}   rZ   ry   _find_dependenciesr   listru   r~   r`   Zroute_by_namesortr   )r   rL  r   Zroute_reprsZnew_route_reprsr   rl   rm   rn   Zroute_data_typesZroutes_reprrs   Zdatatype_namesZdatatype_namer   Zoutput_types_by_nsZoutput_routes_by_nsr`   Zoutput_route_reprsZwhitelisted_route_reprsrc   rR   rR   rS   r   H  s   






z1IRGenerator._filter_namespaces_by_route_whitelistc                 C   s8   t t}t t}t }|D ]
}| |||| q||fS r-  )r   rR  ru   _find_dependencies_recursive)r   r`   output_typesoutput_routesseentrR   rR   rS   rQ    s   zIRGenerator._find_dependenciesc              	   C   s  ||v rd S t |rd S t|st|r|| ||jj | |jD ]}| j|||||d q%|j	d ur@| |j	||| |j
d urt| j|j
|jj\}}|D ]
}	| |	||| qS| D ](\}
}| jj|
 }|D ]}||
 | ||}|D ]
}| |||| q~qnqbt|r| r| D ]}| j|||||d qd S d S d S t|st|r(t||d uksJ t|r|jj}n|jj}|| | |j||| |j
d ur$t| j|j
|\}}|D ]
}	| |	||| q| D ],\}
}| jj|
 }|D ]}||
 | ||}|D ]}| |||| qqqd S d S t|s2t|rB|| | |j||| d S t|r`|| | |j||| | |j||| d S J d| )N)rD  FzUnexpected type in: %s)r    r!   r#   rz   r   r~   rW   rA  rT  r  r]   rV   r\   rX   rY   rZ   r5  r6  r   r   r   r   r   r   Zkey_data_typer  )r   r   rW  rU  rV  rD  rr   Z	doc_typesra   rX  r   rc   Zroute_namespacers   Zroute_typesZ
route_typer7  r^   rR   rR   rS   rT    s   













z(IRGenerator._find_dependencies_recursiverR   )FNFr-  )>r   r   r   r   r   r   r   r   r   r%   r&   r-   r1   r2   r3   r7   r`   r   r3  r   r   r   r   r   classmethodr   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r   r   r  r  r  r)  r   r   r+  r   r   r   r   r   r8  r   rF  rG  r  r   rQ  rT  rR   rR   rR   rS   r      s|    
 
/
!!.@#8E$@) 
CR'0
r#'k	r   rY  )_
__future__r   r   r   r   collectionsr   r2  r   r   Z_MYPYtyping	importlibimport_moduler{   r   Zirr	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   	exceptionr;   astr<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rT   rf   ro   rV   compilerv   rC  r   dictr   objectr   rR   rR   rR   rS   <module>   s<    4@
 

@	