pub fn call(
    scope: &mut ScopeStack,
    method_name: Identifier,
    args: FuncArgs,
    target: Target,
) -> OperationsResult {
    // The first stage of calling a function is finding an implementation that matches the correct
    // function signature.
    let method_args_types = args.iter().map(|arg| match *arg {
        //TODO: Update this when more numeric types are added
        ScopeItem::NumericLiteral(..) => FuncArgType::Arg(scope.primitives().u8()),
        ScopeItem::ByteLiteral(..) => FuncArgType::Array {item: scope.primitives().u8(), size: None},
        ScopeItem::Array {item, ..} => FuncArgType::Array {item: item, size: None},
        ref arg => FuncArgType::Arg(arg.type_id()),
    }).collect();

    let (target_type, target_memory) = match target {
        Target::TypedBlock {type_id, memory} => (type_id, memory),
        //TODO: This requires some significant refactoring, so it has been left out for now
        Target::Array {..} => unreachable!("Returning arrays from functions is not supported yet"),
    };

    // TODO: Since we don't have proper generics, we just search through and try every function
    // with the given name to see if its arguments match. This is more similar to what C++ does
    // than Rust, but it works for the timebeing.
    // We keep searching until we find something that matches or we return the first error.
    scope.lookup(&method_name).into_iter().fold(Err(Error::UnresolvedName(method_name.clone())), |acc, item| acc.or_else(|err| match *item {
        ScopeItem::BuiltInFunction {type_id, ref operations} => {
            let method_type = scope.get_type(type_id);
            if method_type.matches_signature(&method_args_types, target_type) {
                Ok(operations.clone())
            }
            else {
                // If we have at least one matching item, the error should not be UnresolvedName
                // anymore. Only the latest (first) match is considered for this.
                Err(match err {
                    Error::UnresolvedName(..) => Error::MismatchedTypes {
                        expected: ItemType::Function {
                            args: method_args_types.clone(),
                            return_type: target_type,
                        },
                        found: method_type.clone(),
                    },
                    _ => err,
                })
            }
        },
        // If we have at least one matching item, the error should not be UnresolvedName
        // anymore. Only the latest (first) match is considered for this.
        ref item => Err(match err {
            Error::UnresolvedName(..) => Error::MismatchedTypes {
                expected: ItemType::Function {
                    args: method_args_types.clone(),
                    return_type: target_type,
                },
                found: match *item {
                    //TODO: Update this when more numeric types are added
                    ScopeItem::NumericLiteral(..) => scope.get_type(scope.primitives().u8()).clone(),
                    ScopeItem::ByteLiteral(ref bytes) => ItemType::Array {item: Some(scope.primitives().u8()), size: Some(bytes.len())},
                    ScopeItem::Array {item, size, ..} => ItemType::Array {item: Some(item), size: Some(size)},
                    ref arg => scope.get_type(arg.type_id()).clone(),
                },
            },
            _ => err,
        }),
    })).and_then(|operations| (*operations)(scope, args, target_memory))
}
/// Call the provided method with the given arguments
Call the provided method with the given arguments
Call the provided method with the given arguments
pub fn call(
    scope: &mut ScopeStack,
    method_name: Identifier,
    args: FuncArgs,
    target: Target,
) -> OperationsResult {
    // The first stage of calling a function is finding an implementation that matches the correct
    // function signature.
    let method_args_types = args.iter().map(|arg| match *arg {
        //TODO: Update this when more numeric types are added
        ScopeItem::NumericLiteral(..) => FuncArgType::Arg(scope.primitives().u8()),
        ScopeItem::ByteLiteral(..) => FuncArgType::Array {item: scope.primitives().u8(), size: None},
        ScopeItem::Array {item, ..} => FuncArgType::Array {item: item, size: None},
        ref arg => FuncArgType::Arg(arg.type_id()),
    }).collect();
    let (target_type, target_memory) = match target {
        Target::TypedBlock {type_id, memory} => (type_id, memory),
        //TODO: This requires some significant refactoring, so it has been left out for now
        Target::Array {..} => unreachable!("Returning arrays from functions is not supported yet"),
    };
    // TODO: Since we don't have proper generics, we just search through and try every function
    // with the given name to see if its arguments match. This is more similar to what C++ does
    // than Rust, but it works for the timebeing.
    // We keep searching until we find something that matches or we return the first error.
    scope.lookup(&method_name).into_iter().fold(Err(Error::UnresolvedName(method_name.clone())), |acc, item| acc.or_else(|err| match *item {
        ScopeItem::BuiltInFunction {type_id, ref operations} => {
            let method_type = scope.get_type(type_id);
            if method_type.matches_signature(&method_args_types, target_type) {
                Ok(operations.clone())
            }
            else {
                // If we have at least one matching item, the error should not be UnresolvedName
                // anymore. Only the latest (first) match is considered for this.
                Err(match err {
                    Error::UnresolvedName(..) => Error::MismatchedTypes {
                        expected: ItemType::Function {
                            args: method_args_types.clone(),
                            return_type: target_type,
                        },
                        found: method_type.clone(),
                    },
                    _ => err,
                })
            }
        },
        // If we have at least one matching item, the error should not be UnresolvedName
        // anymore. Only the latest (first) match is considered for this.
        ref item => Err(match err {
            Error::UnresolvedName(..) => Error::MismatchedTypes {
                expected: ItemType::Function {
                    args: method_args_types.clone(),
                    return_type: target_type,
                },
                found: match *item {
                    //TODO: Update this when more numeric types are added
                    ScopeItem::NumericLiteral(..) => scope.get_type(scope.primitives().u8()).clone(),
                    ScopeItem::ByteLiteral(ref bytes) => ItemType::Array {item: Some(scope.primitives().u8()), size: Some(bytes.len())},
                    ScopeItem::Array {item, size, ..} => ItemType::Array {item: Some(item), size: Some(size)},
                    ref arg => scope.get_type(arg.type_id()).clone(),
                },
            },
            _ => err,
        }),
    })).and_then(|operations| (*operations)(scope, args, target_memory))
}
pub fn call ( scope : & mut ScopeStack , method_name : Identifier , args : FuncArgs , target : Target , ) -> OperationsResult { // The first stage of calling a function is finding an implementation that matches the correct // function signature. let method_args_types = args . iter ( ) . map ( | arg | match * arg { //TODO: Update this when more numeric types are added ScopeItem :: NumericLiteral ( .. ) => FuncArgType :: Arg ( scope . primitives ( ) . u8 ( ) ) , ScopeItem :: ByteLiteral ( .. ) => FuncArgType :: Array { item : scope . primitives ( ) . u8 ( ) , size : None } , ScopeItem :: Array { item , .. } => FuncArgType :: Array { item : item , size : None } , ref arg => FuncArgType :: Arg ( arg . type_id ( ) ) , } ) . collect ( ) ; let ( target_type , target_memory ) = match target { Target :: TypedBlock { type_id , memory } => ( type_id , memory ) , //TODO: This requires some significant refactoring, so it has been left out for now Target :: Array { .. } => unreachable ! ( " " ) , } ; // TODO: Since we don't have proper generics, we just search through and try every function // with the given name to see if its arguments match. This is more similar to what C++ does // than Rust, but it works for the timebeing. // We keep searching until we find something that matches or we return the first error. scope . lookup ( & method_name ) . into_iter ( ) . fold ( Err ( Error :: UnresolvedName ( method_name . clone ( ) ) ) , | acc , item | acc . or_else ( | err | match * item { ScopeItem :: BuiltInFunction { type_id , ref operations } => { let method_type = scope . get_type ( type_id ) ; if method_type . matches_signature ( & method_args_types , target_type ) { Ok ( operations . clone ( ) ) } else { // If we have at least one matching item, the error should not be UnresolvedName // anymore. Only the latest (first) match is considered for this. Err ( match err { Error :: UnresolvedName ( .. ) => Error :: MismatchedTypes { expected : ItemType :: Function { args : method_args_types . clone ( ) , return_type : target_type , } , found : method_type . clone ( ) , } , _ => err , } ) } } , // If we have at least one matching item, the error should not be UnresolvedName // anymore. Only the latest (first) match is considered for this. ref item => Err ( match err { Error :: UnresolvedName ( .. ) => Error :: MismatchedTypes { expected : ItemType :: Function { args : method_args_types . clone ( ) , return_type : target_type , } , found : match * item { //TODO: Update this when more numeric types are added ScopeItem :: NumericLiteral ( .. ) => scope . get_type ( scope . primitives ( ) . u8 ( ) ) . clone ( ) , ScopeItem :: ByteLiteral ( ref bytes ) => ItemType :: Array { item : Some ( scope . primitives ( ) . u8 ( ) ) , size : Some ( bytes . len ( ) ) } , ScopeItem :: Array { item , size , .. } => ItemType :: Array { item : Some ( item ) , size : Some ( size ) } , ref arg => scope . get_type ( arg . type_id ( ) ) . clone ( ) , } , } , _ => err , } ) , } ) ) . and_then ( | operations | ( * operations ) ( scope , args , target_memory ) ) }
Call the provided method with the given arguments
Call the provided method with the given arguments
scope
&mut ScopeStack
method_name
Identifier
args
FuncArgs
target
Target
scope
&mut ScopeStack
method_name
Identifier
args
FuncArgs
target
Target