Parse a function into a parse context.
(input: &'a str, context: &mut ParseContext)
| 21 | |
| 22 | /// Parse a function into a parse context. |
| 23 | pub fn parse_function<'a>(input: &'a str, context: &mut ParseContext) -> IResult<&'a str, (), StofParseError> { |
| 24 | let mut func = Func::default(); |
| 25 | |
| 26 | // Doc comments & whitespace before a function definition |
| 27 | let (input, mut comments) = doc_comment(input)?; |
| 28 | |
| 29 | let mut do_create_func; |
| 30 | let (input, (attrs, do_insert)) = parse_attributes(input, context)?; |
| 31 | for (k, v) in attrs { func.attributes.insert(k, v); } |
| 32 | do_create_func = do_insert; |
| 33 | |
| 34 | let (input, more_comments) = doc_comment(input)?; |
| 35 | if more_comments.len() > 0 { if comments.len() > 0 { comments.push('\n'); } comments.push_str(&more_comments); } |
| 36 | |
| 37 | let (input, (attrs, do_insert)) = parse_attributes(input, context)?; |
| 38 | for (k, v) in attrs { func.attributes.insert(k, v); } |
| 39 | do_create_func = do_create_func && do_insert; |
| 40 | let (input, _) = whitespace(input)?; // clean up anything more before signature... |
| 41 | |
| 42 | let (input, async_fn) = opt(terminated(tag("async"), multispace0)).parse(input)?; |
| 43 | if async_fn.is_some() && !func.attributes.contains_key(ASYNC_FUNC_ATTR.as_str()) { |
| 44 | func.attributes.insert(ASYNC_FUNC_ATTR.to_string(), Val::Null); |
| 45 | } |
| 46 | |
| 47 | let (input, _) = tag("fn").parse(input)?; |
| 48 | let (input, name) = preceded(multispace0, ident).parse(input).map_err(err_fail)?; |
| 49 | let (input, params) = delimited(char('('), separated_list0(char(','), alt((parameter, opt_parameter))), char(')')).parse(input).map_err(err_fail)?; |
| 50 | let (input, return_type) = opt(preceded(delimited(multispace0, tag("->"), multispace0), parse_type)).parse(input).map_err(err_fail)?; |
| 51 | let (input, instructions) = block(input).map_err(err_fail)?; |
| 52 | |
| 53 | // Check do_create_func now after parse |
| 54 | if !do_create_func { |
| 55 | return Ok((input, ())); |
| 56 | } |
| 57 | |
| 58 | for param in params { func.params.push_back(param); } |
| 59 | func.return_type = return_type.unwrap_or_default(); // default is void |
| 60 | func.instructions = instructions; |
| 61 | |
| 62 | // Is this function an init function (has an #[init] attribute)? |
| 63 | // These functions will get called automatically when the context is dropped (after parse complete). |
| 64 | let mut init_func = false; |
| 65 | if func.attributes.contains_key("init") { init_func = true; } |
| 66 | |
| 67 | // Instert the new function in the current parse context |
| 68 | //println!("({name}){{{func:?}}}"); |
| 69 | let self_ptr = context.self_ptr(); |
| 70 | let func_ref = context.graph.insert_stof_data(&self_ptr, name, Box::new(func), None).expect("failed to insert a parsed function into this context"); |
| 71 | |
| 72 | // Insert init if necessary |
| 73 | if init_func { |
| 74 | context.init_funcs.push(func_ref.clone()); |
| 75 | } |
| 76 | |
| 77 | // Insert the function doc comments also if requested |
| 78 | if context.profile.docs && comments.len() > 0 { |
| 79 | context.graph.insert_stof_data(&self_ptr, &format!("{name}_docs"), Box::new(FuncDoc { |
| 80 | docs: comments, |