mirror of
https://github.com/HigherOrderCO/Kind1.git
synced 2024-08-16 11:50:40 +03:00
feat: added errors for each case
This commit is contained in:
parent
a87a04d5c6
commit
91ed7314a6
@ -150,7 +150,7 @@ pub fn compile_in_session<T>(
|
||||
eprintln!();
|
||||
|
||||
render_to_stderr(
|
||||
&render_config,
|
||||
render_config,
|
||||
&session,
|
||||
&Log::Checking(format!("The file '{}'", file)),
|
||||
);
|
||||
@ -168,12 +168,12 @@ pub fn compile_in_session<T>(
|
||||
contains_error = true;
|
||||
}
|
||||
|
||||
render_to_stderr(&render_config, &session, &diagnostic)
|
||||
render_to_stderr(render_config, &session, &diagnostic)
|
||||
}
|
||||
|
||||
if !contains_error {
|
||||
render_to_stderr(
|
||||
&render_config,
|
||||
render_config,
|
||||
&session,
|
||||
&if compiled {
|
||||
Log::Compiled(start.elapsed())
|
||||
@ -186,7 +186,7 @@ pub fn compile_in_session<T>(
|
||||
|
||||
res
|
||||
} else {
|
||||
render_to_stderr(&render_config, &session, &Log::Failed(start.elapsed()));
|
||||
render_to_stderr(render_config, &session, &Log::Failed(start.elapsed()));
|
||||
eprintln!();
|
||||
|
||||
match res {
|
||||
|
@ -291,7 +291,7 @@ impl<'a> Visitor for Subst<'a> {
|
||||
ExprKind::SeqRecord(sec) => {
|
||||
use kind_tree::concrete::SeqOperation::*;
|
||||
|
||||
self.visit_ident(&mut sec.name);
|
||||
self.visit_expr(&mut sec.expr);
|
||||
|
||||
self.visit_expr(&mut sec.typ);
|
||||
|
||||
|
@ -292,7 +292,7 @@ pub fn check_unbound_top_level(session: &mut Session, book: &mut Book) -> anyhow
|
||||
}
|
||||
|
||||
for unbound in unbound_names.values() {
|
||||
unbound_variable(session, book, &unbound);
|
||||
unbound_variable(session, book, unbound);
|
||||
failed = true;
|
||||
}
|
||||
|
||||
|
@ -886,7 +886,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
let typ = self.parse_atom()?;
|
||||
|
||||
let name = self.parse_id()?;
|
||||
let name = self.parse_atom()?;
|
||||
|
||||
let mut fields = vec![];
|
||||
|
||||
@ -899,9 +899,13 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
let operation = if self.check_and_eat(Token::Eq) {
|
||||
SeqOperation::Set(self.parse_expr(false)?)
|
||||
let expr = self.parse_expr(false)?;
|
||||
end = expr.range;
|
||||
SeqOperation::Set(expr)
|
||||
} else if self.check_and_eat(Token::AtEq) {
|
||||
SeqOperation::Mut(self.parse_expr(false)?)
|
||||
let expr = self.parse_expr(false)?;
|
||||
end = expr.range;
|
||||
SeqOperation::Mut(expr)
|
||||
} else {
|
||||
SeqOperation::Get
|
||||
};
|
||||
@ -910,7 +914,7 @@ impl<'a> Parser<'a> {
|
||||
data: ExprKind::SeqRecord(
|
||||
SeqRecord {
|
||||
typ,
|
||||
name,
|
||||
expr: name,
|
||||
fields,
|
||||
operation,
|
||||
}
|
||||
|
@ -84,70 +84,96 @@ impl<'a> DesugarState<'a> {
|
||||
let typ = self.desugar_expr(&sub.typ);
|
||||
|
||||
let mut value = vec![];
|
||||
self.desugar_record_field_sequence(&mut value, typ, &sub.fields);
|
||||
self.desugar_record_field_sequence(range, &mut value, typ, &sub.fields);
|
||||
|
||||
if self.failed {
|
||||
return Expr::err(range)
|
||||
}
|
||||
|
||||
match &sub.operation {
|
||||
Set(expr) => {
|
||||
let value_ident = Ident::generate("_value");
|
||||
let expr = self.desugar_expr(&expr);
|
||||
|
||||
let mut result = value.iter().rfold(expr, |acc, (name, field)| {
|
||||
let name = name.add_segment(field.to_str()).add_segment("mut");
|
||||
let mut result = value.iter().rfold(expr, |acc, (typ, field)| {
|
||||
let name = typ.add_segment(field.to_str()).add_segment("mut");
|
||||
|
||||
if self.failed || !self.check_implementation(name.to_str(), range, Sugar::Mutter(typ.to_string())) {
|
||||
return desugared::Expr::err(range);
|
||||
}
|
||||
|
||||
self.mk_desugared_ctr(
|
||||
range,
|
||||
name,
|
||||
vec![Expr::var(value_ident.clone()), Expr::lambda(range.clone(), value_ident.clone(), acc, false)],
|
||||
vec![
|
||||
Expr::var(value_ident.clone()),
|
||||
Expr::lambda(range.clone(), value_ident.clone(), acc, false),
|
||||
],
|
||||
false,
|
||||
)
|
||||
});
|
||||
|
||||
match &mut result.data {
|
||||
desugared::ExprKind::Ctr { args, .. } => {
|
||||
if let desugared::ExprKind::Var { name } = &mut args[0].data {
|
||||
*name = sub.name.clone()
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
if let desugared::ExprKind::Ctr { args, .. } = &mut result.data {
|
||||
args[0] = self.desugar_expr(&sub.expr);
|
||||
}
|
||||
|
||||
result
|
||||
},
|
||||
}
|
||||
Mut(expr) => {
|
||||
let value_ident = Ident::generate("_value");
|
||||
let expr = self.desugar_expr(&expr);
|
||||
|
||||
let mut result = value.iter().rfold(expr, |acc, (name, field)| {
|
||||
let name = name.add_segment(field.to_str()).add_segment("mut");
|
||||
Expr::lambda(name.range.clone(), value_ident.clone(), self.mk_desugared_ctr(
|
||||
range,
|
||||
name,
|
||||
vec![Expr::var(value_ident.clone()), acc],
|
||||
|
||||
let result = value.iter().rfold(expr, |acc, (typ, field)| {
|
||||
let name = typ.add_segment(field.to_str()).add_segment("mut");
|
||||
|
||||
if self.failed || !self.check_implementation(name.to_str(), range, Sugar::Mutter(typ.to_string())) {
|
||||
return desugared::Expr::err(range);
|
||||
}
|
||||
|
||||
Expr::lambda(
|
||||
name.range.clone(),
|
||||
value_ident.clone(),
|
||||
self.mk_desugared_ctr(
|
||||
range,
|
||||
name,
|
||||
vec![Expr::var(value_ident.clone()), acc],
|
||||
false,
|
||||
),
|
||||
false,
|
||||
), false)
|
||||
)
|
||||
});
|
||||
|
||||
let mut result = match result.data {
|
||||
desugared::ExprKind::Lambda { body, .. } => {
|
||||
body
|
||||
}
|
||||
_ => panic!()
|
||||
if self.failed {
|
||||
return Expr::err(range)
|
||||
}
|
||||
|
||||
let mut result = if let desugared::ExprKind::Lambda { body, .. } = result.data {
|
||||
body
|
||||
} else {
|
||||
self.send_err(PassDiagnostic::NeedsAField(
|
||||
sub.expr.range.clone()
|
||||
));
|
||||
return Expr::err(range)
|
||||
};
|
||||
|
||||
match &mut result.data {
|
||||
desugared::ExprKind::Ctr { args, .. } => {
|
||||
if let desugared::ExprKind::Var { name } = &mut args[0].data {
|
||||
*name = sub.name.clone()
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
args[0] = self.desugar_expr(&sub.expr);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
Get => value
|
||||
.iter()
|
||||
.fold(Expr::var(sub.name.clone()), |acc, (name, field)| {
|
||||
let name = name.add_segment(field.to_str()).add_segment("get");
|
||||
.fold(self.desugar_expr(&sub.expr), |acc, (typ, field)| {
|
||||
let name = typ.add_segment(field.to_str()).add_segment("get");
|
||||
|
||||
if self.failed || !self.check_implementation(name.to_str(), range, Sugar::Getter(typ.to_string())) {
|
||||
return desugared::Expr::err(range);
|
||||
}
|
||||
|
||||
self.mk_desugared_ctr(range, name, vec![acc], false)
|
||||
}),
|
||||
}
|
||||
|
@ -44,7 +44,9 @@ pub fn desugar_book(
|
||||
name_count: 0,
|
||||
failed: false,
|
||||
};
|
||||
|
||||
state.desugar_book(book);
|
||||
|
||||
if state.failed {
|
||||
Err(GenericPassError.into())
|
||||
} else {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use fxhash::FxHashMap;
|
||||
use kind_span::Range;
|
||||
use kind_tree::{
|
||||
concrete::{self, TopLevel},
|
||||
desugared::{self, Expr},
|
||||
@ -6,7 +7,7 @@ use kind_tree::{
|
||||
telescope::Telescope,
|
||||
};
|
||||
|
||||
use crate::subst::subst_on_expr;
|
||||
use crate::{subst::subst_on_expr, diagnostic::PassDiagnostic};
|
||||
|
||||
use super::DesugarState;
|
||||
|
||||
@ -45,12 +46,13 @@ impl<'a> DesugarState<'a> {
|
||||
|
||||
pub fn desugar_record_field_sequence(
|
||||
&mut self,
|
||||
range: Range,
|
||||
res: &mut Vec<(QualifiedIdent, Ident)>,
|
||||
typ: Box<desugared::Expr>,
|
||||
fields: &[Ident],
|
||||
) {
|
||||
) -> bool {
|
||||
if fields.is_empty() {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some((name, params, record_fields, args)) = self.specialize_on_field(typ.clone()) {
|
||||
@ -70,22 +72,26 @@ impl<'a> DesugarState<'a> {
|
||||
&field
|
||||
.typ
|
||||
.clone()
|
||||
.unwrap_or_else(|| concrete::expr::Expr::typ(field.range.clone())),
|
||||
.unwrap_or_else(|| concrete::expr::Expr::typ(field.range)),
|
||||
);
|
||||
|
||||
|
||||
subst_on_expr(&mut val, pair);
|
||||
|
||||
println!("{}", val);
|
||||
|
||||
res.push((name, key));
|
||||
|
||||
self.desugar_record_field_sequence(res, val, &fields[1..])
|
||||
self.desugar_record_field_sequence(range, res, val, &fields[1..]);
|
||||
return true;
|
||||
} else {
|
||||
panic!("no field")
|
||||
self.send_err(PassDiagnostic::CannotFindTheField(
|
||||
fields[0].range,
|
||||
fields[0].to_string()
|
||||
));
|
||||
}
|
||||
} else {
|
||||
panic!("no record {}", typ)
|
||||
self.send_err(PassDiagnostic::CannotAccessType(
|
||||
fields[0].range,
|
||||
fields[0].to_string()
|
||||
));
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ pub enum Sugar {
|
||||
BoolIf,
|
||||
String,
|
||||
U120,
|
||||
Getter(String),
|
||||
Mutter(String),
|
||||
Match(String),
|
||||
}
|
||||
|
||||
@ -54,6 +56,9 @@ pub enum PassDiagnostic {
|
||||
DuplicatedAttributeArgument(Range, Range),
|
||||
CannotDerive(String, Range),
|
||||
AttributeDoesNotExists(Range),
|
||||
NeedsAField(Range),
|
||||
CannotFindTheField(Range, String),
|
||||
CannotAccessType(Range, String),
|
||||
}
|
||||
|
||||
// TODO: A way to build an error message with methods
|
||||
@ -85,6 +90,9 @@ impl Diagnostic for PassDiagnostic {
|
||||
PassDiagnostic::DuplicatedAttributeArgument(range, _) => Some(range.ctx),
|
||||
PassDiagnostic::CannotDerive(_, range) => Some(range.ctx),
|
||||
PassDiagnostic::AttributeDoesNotExists(range) => Some(range.ctx),
|
||||
PassDiagnostic::NeedsAField(range) => Some(range.ctx),
|
||||
PassDiagnostic::CannotFindTheField(range, _) => Some(range.ctx),
|
||||
PassDiagnostic::CannotAccessType(range, _) => Some(range.ctx),
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,7 +224,9 @@ impl Diagnostic for PassDiagnostic {
|
||||
Sugar::BoolIf => "You must implement 'Bool.if' in order to use the if notation.".to_string(),
|
||||
Sugar::String => "You must implement 'String.cons' in order to use the string notation.".to_string(),
|
||||
Sugar::U120 => "You must implement 'U120.new' in order to use the u120 notation.".to_string(),
|
||||
Sugar::Match(_) => format!("You must implement 'match' in order to use the match notation (or derive match with #derive[match])."),
|
||||
Sugar::Match(_) => "You must implement 'match' in order to use the match notation (or derive match with #derive[match]).".to_string(),
|
||||
Sugar::Mutter(typ) => format!("You must derive 'mutters' for '{}' in order to use this syntax", typ),
|
||||
Sugar::Getter(typ) => format!("You must derive 'getters' for '{}' in order to use this syntax", typ)
|
||||
}],
|
||||
positions: vec![Marker {
|
||||
position: *expr_place,
|
||||
@ -574,7 +584,7 @@ impl Diagnostic for PassDiagnostic {
|
||||
}],
|
||||
},
|
||||
PassDiagnostic::DuplicatedAttributeArgument(first, sec) => DiagnosticFrame {
|
||||
code: 209,
|
||||
code: 210,
|
||||
severity: Severity::Warning,
|
||||
title: "Duplicated attribute argument".to_string(),
|
||||
subtitles: vec![],
|
||||
@ -593,6 +603,48 @@ impl Diagnostic for PassDiagnostic {
|
||||
main: true,
|
||||
}],
|
||||
},
|
||||
PassDiagnostic::NeedsAField(range) => DiagnosticFrame {
|
||||
code: 211,
|
||||
severity: Severity::Error,
|
||||
title: "This expression does not access any field.".to_string(),
|
||||
subtitles: vec![],
|
||||
hints: vec![],
|
||||
positions: vec![Marker {
|
||||
position: *range,
|
||||
color: Color::Fst,
|
||||
text: "Here!".to_string(),
|
||||
no_code: false,
|
||||
main: true,
|
||||
}],
|
||||
},
|
||||
PassDiagnostic::CannotFindTheField(range, _) => DiagnosticFrame {
|
||||
code: 212,
|
||||
severity: Severity::Error,
|
||||
title: "Cannot find the field".to_string(),
|
||||
subtitles: vec![],
|
||||
hints: vec![],
|
||||
positions: vec![Marker {
|
||||
position: *range,
|
||||
color: Color::Fst,
|
||||
text: "Here!".to_string(),
|
||||
no_code: false,
|
||||
main: true,
|
||||
}],
|
||||
},
|
||||
PassDiagnostic::CannotAccessType(range, _) => DiagnosticFrame {
|
||||
code: 213,
|
||||
severity: Severity::Error,
|
||||
title: "Cannot access the type fields.".to_string(),
|
||||
subtitles: vec![],
|
||||
hints: vec!["This syntax only access some types, it does not make complete type directed syntax.".to_string()],
|
||||
positions: vec![Marker {
|
||||
position: *range,
|
||||
color: Color::Fst,
|
||||
text: "Here!".to_string(),
|
||||
no_code: false,
|
||||
main: true,
|
||||
}],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -623,7 +675,10 @@ impl Diagnostic for PassDiagnostic {
|
||||
| AttributeExpectsAValue(_)
|
||||
| DuplicatedAttributeArgument(_, _)
|
||||
| CannotDerive(_, _)
|
||||
| AttributeDoesNotExists(_) => Severity::Error
|
||||
| NeedsAField(_)
|
||||
| CannotFindTheField(_, _)
|
||||
| CannotAccessType(_, _)
|
||||
| AttributeDoesNotExists(_) => Severity::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ fn subst(bindings: im_rc::HashSet<String>, expr: &mut Expr, substs: &FxHashMap<S
|
||||
},
|
||||
Binary { left, right, .. } => {
|
||||
subst(bindings.clone(), left, substs);
|
||||
subst(bindings.clone(), right, substs);
|
||||
subst(bindings, right, substs);
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
@ -471,13 +471,10 @@ impl Visitor for UnboundCollector {
|
||||
fn visit_literal(&mut self, range: Range, lit: &mut kind_tree::concrete::Literal) {
|
||||
use kind_tree::concrete::Literal::*;
|
||||
|
||||
match lit {
|
||||
String(_) => {
|
||||
let string = &mut QualifiedIdent::new_static("String", None, range);
|
||||
self.visit_qualified_ident(&mut string.add_segment("cons").to_generated());
|
||||
self.visit_qualified_ident(&mut string.add_segment("nil").to_generated());
|
||||
}
|
||||
_ => (),
|
||||
if let String(_) = lit {
|
||||
let string = &mut QualifiedIdent::new_static("String", None, range);
|
||||
self.visit_qualified_ident(&mut string.add_segment("cons").to_generated());
|
||||
self.visit_qualified_ident(&mut string.add_segment("nil").to_generated());
|
||||
}
|
||||
}
|
||||
|
||||
@ -640,7 +637,7 @@ impl Visitor for UnboundCollector {
|
||||
|
||||
self.visit_expr(&mut sec.typ);
|
||||
|
||||
self.visit_ident(&mut sec.name);
|
||||
self.visit_expr(&mut sec.expr);
|
||||
|
||||
match &mut sec.operation {
|
||||
Set(expr) => self.visit_expr(expr),
|
||||
|
1
crates/kind-tests/suite/run/GettersSyntax.golden
Normal file
1
crates/kind-tests/suite/run/GettersSyntax.golden
Normal file
@ -0,0 +1 @@
|
||||
100
|
20
crates/kind-tests/suite/run/GettersSyntax.kind2
Normal file
20
crates/kind-tests/suite/run/GettersSyntax.kind2
Normal file
@ -0,0 +1,20 @@
|
||||
type Sum {
|
||||
a
|
||||
b
|
||||
c
|
||||
}
|
||||
|
||||
#derive[getters]
|
||||
record Identity (t: Type) {
|
||||
value: t
|
||||
}
|
||||
|
||||
#derive[getters]
|
||||
record NoTypeVar {
|
||||
some_thing: Identity (Identity U60)
|
||||
}
|
||||
|
||||
Main : U60
|
||||
Main =
|
||||
let f = NoTypeVar.new (Identity.new (Identity.new 100))
|
||||
!NoTypeVar f .some_thing .value .value
|
1
crates/kind-tests/suite/run/MuttersSyntax.golden
Normal file
1
crates/kind-tests/suite/run/MuttersSyntax.golden
Normal file
@ -0,0 +1 @@
|
||||
(NoTypeVar.new (Identity.new (Identity.new 300)))
|
20
crates/kind-tests/suite/run/MuttersSyntax.kind2
Normal file
20
crates/kind-tests/suite/run/MuttersSyntax.kind2
Normal file
@ -0,0 +1,20 @@
|
||||
type Sum {
|
||||
a
|
||||
b
|
||||
c
|
||||
}
|
||||
|
||||
#derive[mutters]
|
||||
record Identity (t: Type) {
|
||||
value: t
|
||||
}
|
||||
|
||||
#derive[mutters]
|
||||
record NoTypeVar {
|
||||
some_thing: Identity (Identity U60)
|
||||
}
|
||||
|
||||
Main : NoTypeVar
|
||||
Main =
|
||||
let f = NoTypeVar.new (Identity.new (Identity.new 100))
|
||||
!NoTypeVar f .some_thing .value .value @= x => (+ x 200)
|
1
crates/kind-tests/suite/run/SettersSyntax.golden
Normal file
1
crates/kind-tests/suite/run/SettersSyntax.golden
Normal file
@ -0,0 +1 @@
|
||||
(NoTypeVar.new (Identity.new (Identity.new 400)))
|
20
crates/kind-tests/suite/run/SettersSyntax.kind2
Normal file
20
crates/kind-tests/suite/run/SettersSyntax.kind2
Normal file
@ -0,0 +1,20 @@
|
||||
type Sum {
|
||||
a
|
||||
b
|
||||
c
|
||||
}
|
||||
|
||||
#derive[mutters]
|
||||
record Identity (t: Type) {
|
||||
value: t
|
||||
}
|
||||
|
||||
#derive[mutters]
|
||||
record NoTypeVar {
|
||||
some_thing: Identity (Identity U60)
|
||||
}
|
||||
|
||||
Main : NoTypeVar
|
||||
Main =
|
||||
let f = NoTypeVar.new (Identity.new (Identity.new 100))
|
||||
!NoTypeVar f .some_thing .value .value = 400
|
@ -146,7 +146,7 @@ pub enum SeqOperation {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SeqRecord {
|
||||
pub typ: Box<Expr>,
|
||||
pub name: Ident,
|
||||
pub expr: Box<Expr>,
|
||||
pub fields: Vec<Ident>,
|
||||
pub operation: SeqOperation
|
||||
}
|
||||
@ -593,7 +593,7 @@ impl Display for Expr {
|
||||
Hole => write!(f, "_"),
|
||||
SeqRecord(rec) => {
|
||||
use SeqOperation::*;
|
||||
write!(f, "(!({}) {} {}", rec.typ, rec.name, rec.fields.iter().map(|x| format!(".{}", x.to_str())).collect::<Vec<_>>().join(","))?;
|
||||
write!(f, "(!({}) {} {}", rec.typ, rec.expr, rec.fields.iter().map(|x| format!(".{}", x.to_str())).collect::<Vec<_>>().join(","))?;
|
||||
match &rec.operation {
|
||||
Set(expr) => write!(f, "+= {})", expr),
|
||||
Mut(expr) => write!(f, "@= {})", expr),
|
||||
|
@ -493,7 +493,7 @@ pub fn walk_expr<T: Visitor>(ctx: &mut T, expr: &mut Expr) {
|
||||
ExprKind::Subst(subst) => ctx.visit_substitution(subst),
|
||||
ExprKind::Match(matcher) => ctx.visit_match(matcher),
|
||||
ExprKind::SeqRecord(seq) => {
|
||||
ctx.visit_ident(&mut seq.name);
|
||||
ctx.visit_expr(&mut seq.expr);
|
||||
ctx.visit_expr(&mut seq.typ);
|
||||
|
||||
match &mut seq.operation {
|
||||
|
Loading…
Reference in New Issue
Block a user