/// Load a file file from the cache, parse and resolve it. The file must be present in
/// the cache. This function is recursive for imports.
Load a file file from the cache, parse and resolve it. The file must be present in
the cache. This function is recursive for imports.
Load a file file from the cache parse and resolve it . The file must be present in the cache . This function is recursive for imports .
pub fn sema(file: ResolvedFile, cache: &mut FileCache, ns: &mut ast::Namespace) {
    let file_no = ns.files.len();
    let source_code = cache.get_file_contents(&file.full_path);
    ns.files.push(file.full_path.clone());
    let pt = match parse(&source_code, file_no) {
        Ok(s) => s,
        Err(errors) => {
            ns.diagnostics.extend(errors);
            return;
        }
    };
    // We need to iterate over the parsed contracts a few times, so create a temporary vector
    // This should be done before the contract types are created so the contract type numbers line up
    let contracts_to_resolve =
        pt.0.iter()
            .filter_map(|part| {
                if let pt::SourceUnitPart::ContractDefinition(def) = part {
                    Some(def)
                } else {
                    None
                }
            })
            .enumerate()
            .map(|(no, def)| (no + ns.contracts.len(), def.as_ref()))
            .collect::<Vec<(usize, &pt::ContractDefinition)>>();
    // first resolve all the types we can find
    let fields = types::resolve_typenames(&pt, file_no, ns);
    // resolve pragmas and imports
    for part in &pt.0 {
        match part {
            pt::SourceUnitPart::PragmaDirective(name, value) => {
                resolve_pragma(name, value, ns);
            }
            pt::SourceUnitPart::ImportDirective(import) => {
                resolve_import(import, Some(&file), file_no, cache, ns);
            }
            _ => (),
        }
    }
    // once all the types are resolved, we can resolve the structs and events. This is because
    // struct fields or event fields can have types defined elsewhere.
    types::resolve_fields(fields, file_no, ns);
    // give up if we failed
    if diagnostics::any_errors(&ns.diagnostics) {
        return;
    }
    // resolve functions/constants outside of contracts
    let mut resolve_bodies = Vec::new();
    for part in &pt.0 {
        match part {
            pt::SourceUnitPart::FunctionDefinition(func) => {
                if let Some(func_no) = functions::function(func, file_no, ns) {
                    resolve_bodies.push((func_no, func));
                }
            }
            pt::SourceUnitPart::VariableDefinition(var) => {
                var_decl(None, var, file_no, None, ns, &mut Symtable::new());
            }
            _ => (),
        }
    }
    // now resolve the contracts
    contracts::resolve(&contracts_to_resolve, file_no, ns);
    // now we can resolve the body of functions outside of contracts
    for (func_no, func) in resolve_bodies {
        let _ = statements::resolve_function_body(func, file_no, None, func_no, ns);
    }
    // check for stray semi colons
    for part in &pt.0 {
        match part {
            pt::SourceUnitPart::StraySemicolon(loc) => {
                ns.diagnostics
                    .push(ast::Diagnostic::error(*loc, "stray semicolon".to_string()));
            }
            pt::SourceUnitPart::ContractDefinition(contract) => {
                for part in &contract.parts {
                    if let pt::ContractPart::StraySemicolon(loc) = part {
                        ns.diagnostics
                            .push(ast::Diagnostic::error(*loc, "stray semicolon".to_string()));
                    }
                }
            }
            _ => (),
        }
    }
    // now check state mutability for all contracts
    mutability::mutablity(file_no, ns);
}
pub fn sema ( file : ResolvedFile , cache : & mut FileCache , ns : & mut ast :: Namespace ) { let file_no = ns . files . len ( ) ; let source_code = cache . get_file_contents ( & file . full_path ) ; ns . files . push ( file . full_path . clone ( ) ) ; let pt = match parse ( & source_code , file_no ) { Ok ( s ) => s , Err ( errors ) => { ns . diagnostics . extend ( errors ) ; return ; } } ; // We need to iterate over the parsed contracts a few times, so create a temporary vector // This should be done before the contract types are created so the contract type numbers line up let contracts_to_resolve = pt . 0 . iter ( ) . filter_map ( | part | { if let pt :: SourceUnitPart :: ContractDefinition ( def ) = part { Some ( def ) } else { None } } ) . enumerate ( ) . map ( | ( no , def ) | ( no + ns . contracts . len ( ) , def . as_ref ( ) ) ) . collect :: < Vec < ( usize , & pt :: ContractDefinition ) > > ( ) ; // first resolve all the types we can find let fields = types :: resolve_typenames ( & pt , file_no , ns ) ; // resolve pragmas and imports for part in & pt . 0 { match part { pt :: SourceUnitPart :: PragmaDirective ( name , value ) => { resolve_pragma ( name , value , ns ) ; } pt :: SourceUnitPart :: ImportDirective ( import ) => { resolve_import ( import , Some ( & file ) , file_no , cache , ns ) ; } _ => ( ) , } } // once all the types are resolved, we can resolve the structs and events. This is because // struct fields or event fields can have types defined elsewhere. types :: resolve_fields ( fields , file_no , ns ) ; // give up if we failed if diagnostics :: any_errors ( & ns . diagnostics ) { return ; } // resolve functions/constants outside of contracts let mut resolve_bodies = Vec :: new ( ) ; for part in & pt . 0 { match part { pt :: SourceUnitPart :: FunctionDefinition ( func ) => { if let Some ( func_no ) = functions :: function ( func , file_no , ns ) { resolve_bodies . push ( ( func_no , func ) ) ; } } pt :: SourceUnitPart :: VariableDefinition ( var ) => { var_decl ( None , var , file_no , None , ns , & mut Symtable :: new ( ) ) ; } _ => ( ) , } } // now resolve the contracts contracts :: resolve ( & contracts_to_resolve , file_no , ns ) ; // now we can resolve the body of functions outside of contracts for ( func_no , func ) in resolve_bodies { let _ = statements :: resolve_function_body ( func , file_no , None , func_no , ns ) ; } // check for stray semi colons for part in & pt . 0 { match part { pt :: SourceUnitPart :: StraySemicolon ( loc ) => { ns . diagnostics . push ( ast :: Diagnostic :: error ( * loc , " " . to_string ( ) ) ) ; } pt :: SourceUnitPart :: ContractDefinition ( contract ) => { for part in & contract . parts { if let pt :: ContractPart :: StraySemicolon ( loc ) = part { ns . diagnostics . push ( ast :: Diagnostic :: error ( * loc , " " . to_string ( ) ) ) ; } } } _ => ( ) , } } // now check state mutability for all contracts mutability :: mutablity ( file_no , ns ) ; }
Load a file file from the cache, parse and resolve it.
Load a file file from the cache parse and resolve it .
file
ResolvedFile
cache
&mut FileCache
ns
&mut ast::Namespace