parse ops

tc
azur 2023-03-29 22:26:08 +07:00
parent 646f9f6bd2
commit 454a31e2e9
3 changed files with 127 additions and 23 deletions

View File

@ -8,9 +8,12 @@ pub mod typing;
fn main() {
let src = "
{
let x: num = 1;
let y: num = 2;
x
let foo : num =
let a : num = true,
b : num = 3
in
a + b;
foo * 2
}
".to_string();
let filename = "?".to_string();
@ -32,7 +35,7 @@ fn main() {
.with_label(Label::new((filename.clone(), ty_err.loc.into_range()))
.with_message(match ty_err.note {
Some(note) => note,
None => "while type checking this expression".to_string(),
None => "While type checking this expression".to_string(),
})
.with_color(Color::Red)
);

View File

@ -356,7 +356,78 @@ pub fn expr_parser<'tokens, 'src: 'tokens>() -> impl Parser<
None => (f.0, f.1),
});
call
let op = choice((
just(Token::Sub).to(UnaryOp::Neg),
just(Token::Not).to(UnaryOp::Not),
));
let unary = op
.map_with_span(|op, s| (op, s))
.repeated()
.foldr(
call,
|op, expr| {
let span = op.1.start..expr.1.end;
(Expr::Unary(op.0, boxspan(expr)), span.into())
});
let op = choice((
just(Token::Mul).to(BinaryOp::Mul),
just(Token::Div).to(BinaryOp::Div),
));
let product = unary.clone()
.foldl(
op.then(unary).repeated(),
|a, (op, b)| {
let span = a.1.start..b.1.end;
(Expr::Binary(op, boxspan(a), boxspan(b)), span.into())
}
);
let op = choice((
just(Token::Add).to(BinaryOp::Add),
just(Token::Sub).to(BinaryOp::Sub),
));
let sum = product.clone()
.foldl(
op.then(product).repeated(),
|a, (op, b)| {
let span = a.1.start..b.1.end;
(Expr::Binary(op, boxspan(a), boxspan(b)), span.into())
}
);
let op = choice((
just(Token::Eq).to(BinaryOp::Eq),
just(Token::Ne).to(BinaryOp::Ne),
just(Token::Lt).to(BinaryOp::Lt),
just(Token::Le).to(BinaryOp::Le),
just(Token::Gt).to(BinaryOp::Gt),
just(Token::Ge).to(BinaryOp::Ge),
));
let comparison = sum.clone()
.foldl(
op.then(sum).repeated(),
|a, (op, b)| {
let span = a.1.start..b.1.end;
(Expr::Binary(op, boxspan(a), boxspan(b)), span.into())
}
);
let op = choice((
just(Token::And).to(BinaryOp::And),
just(Token::Or).to(BinaryOp::Or),
));
let logical = comparison.clone()
.foldl(
op.then(comparison).repeated(),
|a, (op, b)| {
let span = a.1.start..b.1.end;
(Expr::Binary(op, boxspan(a), boxspan(b)), span.into())
}
);
#[allow(clippy::let_and_return)]
logical
})
}

View File

@ -101,7 +101,7 @@ fn type_expr<'src>(
Expr::Ident(name) => {
let ty = env.lookup(name)
.ok_or(TypeError::new(format!("unknown identifier `{}`", name), expr.1))?;
.ok_or(TypeError::new(format!("Unknown identifier `{}`", name), expr.1))?;
oks!(TExpr::Ident(name, ty))
}
@ -112,6 +112,12 @@ fn type_expr<'src>(
UnaryOp::Not => Type::Bool,
};
if te.0.ty() != &ret_ty {
return Err(TypeError::new(format!("Expected `{}` but found `{}`", ret_ty, te.0.ty()), te.1)
.with_note(format!("This have type `{}`", te.0.ty()))
.with_hint(format!("This operator requires a `{}`", ret_ty), (te.1.start-1..te.1.start).into()));
}
oks!(TExpr::Unary {
op,
expr: sbox!(te),
@ -122,22 +128,46 @@ fn type_expr<'src>(
Expr::Binary(op, lhs, rhs) => {
let tlhs = type_expr(env, unbox!(lhs))?;
let trhs = type_expr(env, unbox!(rhs))?;
let ret_ty = match op {
let op_ty = match op {
BinaryOp::Add
| BinaryOp::Sub
| BinaryOp::Mul
| BinaryOp::Div
| BinaryOp::Rem => Type::Num,
| BinaryOp::Rem => Some(Type::Num),
BinaryOp::And
| BinaryOp::Or => Type::Bool,
| BinaryOp::Or => Some(Type::Bool),
BinaryOp::Eq
| BinaryOp::Ne
| BinaryOp::Lt
| BinaryOp::Le
| BinaryOp::Gt
| BinaryOp::Ge => Type::Bool,
| BinaryOp::Ge => None,
};
let ret_ty;
if let Some(op_ty) = op_ty {
if tlhs.0.ty() != &op_ty {
return Err(TypeError::new(format!("Expected `{}` but found `{}`", op_ty, tlhs.0.ty()), tlhs.1)
.with_note(format!("This have type `{}`", tlhs.0.ty()))
.with_hint(format!("This operator requires a `{}`", op_ty), (tlhs.1.start-1..tlhs.1.start).into()));
}
if trhs.0.ty() != &op_ty {
return Err(TypeError::new(format!("Expected `{}` but found `{}`", op_ty, trhs.0.ty()), trhs.1)
.with_note(format!("This have type `{}`", trhs.0.ty()))
.with_hint(format!("This operator requires a `{}`", op_ty), (trhs.1.start-1..trhs.1.start).into()));
}
ret_ty = op_ty;
} else {
if tlhs.0.ty() != trhs.0.ty() {
return Err(TypeError::new(format!("Expected `{}` but found `{}`", tlhs.0.ty(), trhs.0.ty()), trhs.1)
.with_hint(
format!("Both have to be the same type. Got `{}` and `{}`", tlhs.0.ty(), trhs.0.ty()),
(tlhs.1.start..trhs.1.end).into(),
));
}
ret_ty = Type::Bool;
}
oks!(TExpr::Binary {
op,
lhs: sbox!(tlhs),
@ -199,17 +229,17 @@ fn type_expr<'src>(
if param_tys.len() != targs.len() {
return Err(TypeError::new(
format!(
"expected {} arguments, got {}",
"Expected {} arguments, got {}",
param_tys.len(),
targs.len(),
),
args_span.into(),
).with_note(format!(
"expected {} arguments",
"Expected {} arguments",
param_tys.len(),
)).with_hint(
format!(
"this expect arguments of type `{}`",
"This expect arguments of type `{}`",
param_tys.iter().map(|ty| ty.to_string()).collect::<Vec<_>>().join(", ")
),
func.1,
@ -221,13 +251,13 @@ fn type_expr<'src>(
if arg.0.ty() != param {
return Err(TypeError::new(
format!(
"expected argument of type `{}`, got `{}`",
"Expected argument of type `{}`, got `{}`",
param,
arg.0.ty(),
),
arg.1,
).with_note(format!(
"expected argument of type `{}`",
"Expected argument of type `{}`",
param,
)));
}
@ -241,7 +271,7 @@ fn type_expr<'src>(
})
} else {
Err(TypeError::new(
format!("expected function, got `{}`", tfunc.0.ty()),
format!("Expected function, got `{}`", tfunc.0.ty()),
tfunc.1,
))
}
@ -255,7 +285,7 @@ fn type_expr<'src>(
// Check if the condition is of type `bool`.
if tcond.0.ty() != &Type::Bool {
return Err(TypeError::new(
format!("expected condition of type `bool`, got `{}`", tcond.0.ty()),
format!("Expected condition of type `bool`, got `{}`", tcond.0.ty()),
tcond.1,
));
}
@ -264,13 +294,13 @@ fn type_expr<'src>(
if tt.0.ty() != tf.0.ty() {
return Err(TypeError::new(
format!(
"expected the branches to have the same type, got `{}` and `{}`",
"Expected the branches to have the same type, got `{}` and `{}`",
tt.0.ty(),
tf.0.ty(),
),
tf.1,
).with_note(format!(
"expected this branch to be type of `{}`",
"Expected this branch to be type of `{}`",
tt.0.ty(),
)));
}
@ -300,13 +330,13 @@ fn type_expr<'src>(
if texpr.0.ty() != &ty {
return Err(TypeError::new(
format!(
"expected the binding to be of type `{}`, got `{}`",
"Expected the value to be of type `{}`, got `{}`",
ty,
texpr.0.ty(),
),
texpr.1,
).with_note(format!(
"expected this binding to be of type `{}`",
"Expected this value to be of type `{}`",
ty,
)));
}
@ -339,13 +369,13 @@ fn type_expr<'src>(
if texpr.0.ty() != &ty {
return Err(TypeError::new(
format!(
"expected the binding to be of type `{}`, got `{}`",
"Expected the binding to be of type `{}`, got `{}`",
ty,
texpr.0.ty(),
),
texpr.1,
).with_note(format!(
"expected this binding to be of type `{}`",
"Expected this binding to be of type `{}`",
ty,
)));
}