Add dot syntax for associated functions
This commit is contained in:
		
							parent
							
								
									7e3a13cf55
								
							
						
					
					
						commit
						1c83ca44ab
					
				
							
								
								
									
										27
									
								
								examples/associated_functions_shorthand.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								examples/associated_functions_shorthand.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | import std::print; | ||||||
|  | import std::from_str; | ||||||
|  | import std::String; | ||||||
|  | 
 | ||||||
|  | struct Otus { | ||||||
|  |     field: u32, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Otus { | ||||||
|  |     fn test(self) -> u32 { | ||||||
|  |         self.field | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl i32 { | ||||||
|  |     fn test(self) -> u32 { | ||||||
|  |         43 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> u32 { | ||||||
|  |     let otus = Otus { field: 17 }; | ||||||
|  |     print(from_str("otus: ") + otus.test() as u64); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     return otus.test(); | ||||||
|  | } | ||||||
| @ -89,6 +89,8 @@ pub enum ExpressionKind { | |||||||
|     Indexed(Box<Expression>, Box<Expression>), |     Indexed(Box<Expression>, Box<Expression>), | ||||||
|     /// Struct-accessed, e.g. <expr>.<expr>
 |     /// Struct-accessed, e.g. <expr>.<expr>
 | ||||||
|     Accessed(Box<Expression>, String), |     Accessed(Box<Expression>, String), | ||||||
|  |     /// Associated function call, but with a shorthand
 | ||||||
|  |     AccessCall(Box<Expression>, Box<FunctionCallExpression>), | ||||||
|     Binop(BinaryOperator, Box<Expression>, Box<Expression>), |     Binop(BinaryOperator, Box<Expression>, Box<Expression>), | ||||||
|     FunctionCall(Box<FunctionCallExpression>), |     FunctionCall(Box<FunctionCallExpression>), | ||||||
|     AssociatedFunctionCall(Type, Box<FunctionCallExpression>), |     AssociatedFunctionCall(Type, Box<FunctionCallExpression>), | ||||||
|  | |||||||
| @ -358,12 +358,20 @@ impl Parse for PrimaryExpression { | |||||||
|                         stream.get_range().unwrap(), |                         stream.get_range().unwrap(), | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 ValueIndex::Struct(StructValueIndex(name)) => { |                 ValueIndex::Dot(val) => match val { | ||||||
|                     expr = Expression( |                     DotIndexKind::StructValueIndex(name) => { | ||||||
|                         ExpressionKind::Accessed(Box::new(expr), name), |                         expr = Expression( | ||||||
|                         stream.get_range().unwrap(), |                             ExpressionKind::Accessed(Box::new(expr), name), | ||||||
|                     ); |                             stream.get_range().unwrap(), | ||||||
|                 } |                         ); | ||||||
|  |                     } | ||||||
|  |                     DotIndexKind::FunctionCall(function_call_expression) => { | ||||||
|  |                         expr = Expression( | ||||||
|  |                             ExpressionKind::AccessCall(Box::new(expr), Box::new(function_call_expression)), | ||||||
|  |                             stream.get_range().unwrap(), | ||||||
|  |                         ); | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -473,27 +481,35 @@ impl Parse for BinaryOperator { | |||||||
| impl Parse for FunctionCallExpression { | impl Parse for FunctionCallExpression { | ||||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { |     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||||
|         if let Some(Token::Identifier(name)) = stream.next() { |         if let Some(Token::Identifier(name)) = stream.next() { | ||||||
|             stream.expect(Token::ParenOpen)?; |             let args = stream.parse::<FunctionArgs>()?; | ||||||
| 
 |             Ok(FunctionCallExpression(name, args.0, stream.get_range().unwrap())) | ||||||
|             let mut args = Vec::new(); |  | ||||||
| 
 |  | ||||||
|             if let Ok(exp) = stream.parse() { |  | ||||||
|                 args.push(exp); |  | ||||||
| 
 |  | ||||||
|                 while stream.expect(Token::Comma).is_ok() { |  | ||||||
|                     args.push(stream.parse()?); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             stream.expect(Token::ParenClose)?; |  | ||||||
| 
 |  | ||||||
|             Ok(FunctionCallExpression(name, args, stream.get_range().unwrap())) |  | ||||||
|         } else { |         } else { | ||||||
|             Err(stream.expected_err("identifier")?) |             Err(stream.expected_err("identifier")?) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct FunctionArgs(Vec<Expression>); | ||||||
|  | 
 | ||||||
|  | impl Parse for FunctionArgs { | ||||||
|  |     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||||
|  |         stream.expect(Token::ParenOpen)?; | ||||||
|  | 
 | ||||||
|  |         let mut params = Vec::new(); | ||||||
|  |         if let Ok(exp) = stream.parse() { | ||||||
|  |             params.push(exp); | ||||||
|  | 
 | ||||||
|  |             while stream.expect(Token::Comma).is_ok() { | ||||||
|  |                 params.push(stream.parse()?); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         stream.expect(Token::ParenClose)?; | ||||||
|  | 
 | ||||||
|  |         Ok(FunctionArgs(params)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl Parse for IfExpression { | impl Parse for IfExpression { | ||||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { |     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||||
|         stream.expect(Token::If)?; |         stream.expect(Token::If)?; | ||||||
| @ -766,14 +782,14 @@ impl<T: Parse + std::fmt::Debug> Parse for NamedField<T> { | |||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub enum ValueIndex { | pub enum ValueIndex { | ||||||
|     Array(ArrayValueIndex), |     Array(ArrayValueIndex), | ||||||
|     Struct(StructValueIndex), |     Dot(DotIndexKind), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Parse for ValueIndex { | impl Parse for ValueIndex { | ||||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { |     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||||
|         match stream.peek() { |         match stream.peek() { | ||||||
|             Some(Token::BracketOpen) => Ok(ValueIndex::Array(stream.parse()?)), |             Some(Token::BracketOpen) => Ok(ValueIndex::Array(stream.parse()?)), | ||||||
|             Some(Token::Dot) => Ok(ValueIndex::Struct(stream.parse()?)), |             Some(Token::Dot) => Ok(ValueIndex::Dot(stream.parse()?)), | ||||||
|             _ => Err(stream.expecting_err("value or struct index")?), |             _ => Err(stream.expecting_err("value or struct index")?), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -792,13 +808,24 @@ impl Parse for ArrayValueIndex { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub struct StructValueIndex(String); | pub enum DotIndexKind { | ||||||
|  |     StructValueIndex(String), | ||||||
|  |     FunctionCall(FunctionCallExpression), | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| impl Parse for StructValueIndex { | impl Parse for DotIndexKind { | ||||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { |     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||||
|         stream.expect(Token::Dot)?; |         stream.expect(Token::Dot)?; | ||||||
|         if let Some(Token::Identifier(name)) = stream.next() { |         if let Some(Token::Identifier(name)) = stream.next() { | ||||||
|             Ok(StructValueIndex(name)) |             if let Ok(args) = stream.parse::<FunctionArgs>() { | ||||||
|  |                 Ok(Self::FunctionCall(FunctionCallExpression( | ||||||
|  |                     name, | ||||||
|  |                     args.0, | ||||||
|  |                     stream.get_range_prev().unwrap(), | ||||||
|  |                 ))) | ||||||
|  |             } else { | ||||||
|  |                 Ok(Self::StructValueIndex(name)) | ||||||
|  |             } | ||||||
|         } else { |         } else { | ||||||
|             return Err(stream.expected_err("struct index (number)")?); |             return Err(stream.expected_err("struct index (number)")?); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -422,6 +422,19 @@ impl ast::Expression { | |||||||
|                     meta: fn_call_expr.2.as_meta(module_id), |                     meta: fn_call_expr.2.as_meta(module_id), | ||||||
|                 }, |                 }, | ||||||
|             ), |             ), | ||||||
|  |             ast::ExpressionKind::AccessCall(expression, fn_call_expr) => { | ||||||
|  |                 let mut params: Vec<_> = fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(); | ||||||
|  |                 params.insert(0, expression.process(module_id)); | ||||||
|  |                 mir::ExprKind::AssociatedFunctionCall( | ||||||
|  |                     mir::TypeKind::Vague(mir::VagueType::Unknown), | ||||||
|  |                     mir::FunctionCall { | ||||||
|  |                         name: fn_call_expr.0.clone(), | ||||||
|  |                         return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), | ||||||
|  |                         parameters: params, | ||||||
|  |                         meta: fn_call_expr.2.as_meta(module_id), | ||||||
|  |                     }, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         mir::Expression(kind, self.1.as_meta(module_id)) |         mir::Expression(kind, self.1.as_meta(module_id)) | ||||||
|  | |||||||
| @ -82,6 +82,8 @@ pub enum ErrorKind { | |||||||
|     BinaryOpAlreadyDefined(BinaryOperator, TypeKind, TypeKind), |     BinaryOpAlreadyDefined(BinaryOperator, TypeKind, TypeKind), | ||||||
|     #[error("Binary operation {0} between {1} and {2} is not defined")] |     #[error("Binary operation {0} between {1} and {2} is not defined")] | ||||||
|     InvalidBinop(BinaryOperator, TypeKind, TypeKind), |     InvalidBinop(BinaryOperator, TypeKind, TypeKind), | ||||||
|  |     #[error("Could not infer type for {0:?}. Try adding type annotations.")] | ||||||
|  |     CouldNotInferType(String), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Debug, PartialEq, Eq)] | #[derive(Clone, Debug, PartialEq, Eq)] | ||||||
| @ -294,13 +296,13 @@ impl TypeKind { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub(super) fn assert_known(&self, refs: &TypeRefs, state: &TypecheckPassState) -> Result<TypeKind, ErrorKind> { |     pub(super) fn assert_known(&self, state: &TypecheckPassState) -> Result<TypeKind, ErrorKind> { | ||||||
|         self.is_known(refs, state).map(|_| self.clone()) |         self.is_known(state).map(|_| self.clone()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub(super) fn is_known(&self, refs: &TypeRefs, state: &TypecheckPassState) -> Result<(), ErrorKind> { |     pub(super) fn is_known(&self, state: &TypecheckPassState) -> Result<(), ErrorKind> { | ||||||
|         match &self { |         match &self { | ||||||
|             TypeKind::Array(type_kind, _) => type_kind.as_ref().is_known(refs, state), |             TypeKind::Array(type_kind, _) => type_kind.as_ref().is_known(state), | ||||||
|             TypeKind::CustomType(custom_type_key) => { |             TypeKind::CustomType(custom_type_key) => { | ||||||
|                 state |                 state | ||||||
|                     .scope |                     .scope | ||||||
| @ -311,9 +313,9 @@ impl TypeKind { | |||||||
|                         state.module_id.unwrap(), |                         state.module_id.unwrap(), | ||||||
|                     )) |                     )) | ||||||
|             } |             } | ||||||
|             TypeKind::Borrow(type_kind, _) => type_kind.is_known(refs, state), |             TypeKind::Borrow(type_kind, _) => type_kind.is_known(state), | ||||||
|             TypeKind::UserPtr(type_kind) => type_kind.is_known(refs, state), |             TypeKind::UserPtr(type_kind) => type_kind.is_known(state), | ||||||
|             TypeKind::CodegenPtr(type_kind) => type_kind.is_known(refs, state), |             TypeKind::CodegenPtr(type_kind) => type_kind.is_known(state), | ||||||
|             TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(*vague_type)), |             TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(*vague_type)), | ||||||
|             _ => Ok(()), |             _ => Ok(()), | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -112,7 +112,7 @@ impl BinopDefinition { | |||||||
|     fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> { |     fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> { | ||||||
|         for param in vec![&self.lhs, &self.rhs] { |         for param in vec![&self.lhs, &self.rhs] { | ||||||
|             let param_t = state.or_else( |             let param_t = state.or_else( | ||||||
|                 param.1.assert_known(typerefs, state), |                 param.1.assert_known(state), | ||||||
|                 TypeKind::Vague(Vague::Unknown), |                 TypeKind::Vague(Vague::Unknown), | ||||||
|                 self.signature(), |                 self.signature(), | ||||||
|             ); |             ); | ||||||
| @ -130,7 +130,7 @@ impl BinopDefinition { | |||||||
|             state.ok(res, self.signature()); |             state.ok(res, self.signature()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let return_type = self.return_type.clone().assert_known(typerefs, state)?; |         let return_type = self.return_type.clone().assert_known(state)?; | ||||||
| 
 | 
 | ||||||
|         state.scope.return_type_hint = Some(self.return_type.clone()); |         state.scope.return_type_hint = Some(self.return_type.clone()); | ||||||
|         let inferred = self |         let inferred = self | ||||||
| @ -150,7 +150,7 @@ impl FunctionDefinition { | |||||||
|     fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> { |     fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> { | ||||||
|         for param in &self.parameters { |         for param in &self.parameters { | ||||||
|             let param_t = state.or_else( |             let param_t = state.or_else( | ||||||
|                 param.1.assert_known(typerefs, state), |                 param.1.assert_known(state), | ||||||
|                 TypeKind::Vague(Vague::Unknown), |                 TypeKind::Vague(Vague::Unknown), | ||||||
|                 self.signature(), |                 self.signature(), | ||||||
|             ); |             ); | ||||||
| @ -168,7 +168,7 @@ impl FunctionDefinition { | |||||||
|             state.ok(res, self.signature()); |             state.ok(res, self.signature()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let return_type = self.return_type.clone().assert_known(typerefs, state)?; |         let return_type = self.return_type.clone().assert_known(state)?; | ||||||
|         let inferred = self.kind.typecheck(typerefs, state, Some(self.return_type.clone())); |         let inferred = self.kind.typecheck(typerefs, state, Some(self.return_type.clone())); | ||||||
| 
 | 
 | ||||||
|         match inferred { |         match inferred { | ||||||
| @ -327,7 +327,7 @@ impl Block { | |||||||
|                 } |                 } | ||||||
|                 StmtKind::While(WhileStatement { condition, block, meta }) => { |                 StmtKind::While(WhileStatement { condition, block, meta }) => { | ||||||
|                     let condition_ty = condition.typecheck(&mut state, typerefs, HintKind::Coerce(TypeKind::Bool))?; |                     let condition_ty = condition.typecheck(&mut state, typerefs, HintKind::Coerce(TypeKind::Bool))?; | ||||||
|                     if condition_ty.assert_known(typerefs, &state)? != TypeKind::Bool { |                     if condition_ty.assert_known(&state)? != TypeKind::Bool { | ||||||
|                         state.note_errors(&vec![ErrorKind::TypesIncompatible(condition_ty, TypeKind::Bool)], *meta); |                         state.note_errors(&vec![ErrorKind::TypesIncompatible(condition_ty, TypeKind::Bool)], *meta); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -595,6 +595,19 @@ impl Expression { | |||||||
|                 Ok(type_refs.from_type(type_kind).unwrap()) |                 Ok(type_refs.from_type(type_kind).unwrap()) | ||||||
|             } |             } | ||||||
|             ExprKind::AssociatedFunctionCall(type_kind, function_call) => { |             ExprKind::AssociatedFunctionCall(type_kind, function_call) => { | ||||||
|  |                 if type_kind.is_known(state).is_err() { | ||||||
|  |                     let first_param = function_call | ||||||
|  |                         .parameters | ||||||
|  |                         .get_mut(0) | ||||||
|  |                         .expect("Unknown-type associated function NEEDS to always have at least one parameter!"); | ||||||
|  |                     let param_ty = first_param.infer_types(state, type_refs).unwrap().resolve_deep(); | ||||||
|  |                     *type_kind = state.or_else( | ||||||
|  |                         param_ty.ok_or(ErrorKind::CouldNotInferType(format!("{}", first_param))), | ||||||
|  |                         Void, | ||||||
|  |                         first_param.1, | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 // Get function definition and types
 |                 // Get function definition and types
 | ||||||
|                 let fn_call = state |                 let fn_call = state | ||||||
|                     .scope |                     .scope | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user