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

View File

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