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 {
|
||||||
|
DotIndexKind::StructValueIndex(name) => {
|
||||||
expr = Expression(
|
expr = Expression(
|
||||||
ExpressionKind::Accessed(Box::new(expr), name),
|
ExpressionKind::Accessed(Box::new(expr), name),
|
||||||
stream.get_range().unwrap(),
|
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