feat: Emit keyword
This commit is contained in:
parent
23713ce6fa
commit
d25b8f91c7
|
@ -205,6 +205,7 @@ fn str_to_keyword(word: &str) -> Option<Token> {
|
|||
"todo" => Some(Token::Todo),
|
||||
"type" => Some(Token::Type),
|
||||
"trace" => Some(Token::Trace),
|
||||
"emit" => Some(Token::Emit),
|
||||
"test" => Some(Token::Test),
|
||||
// TODO: remove this in a future release
|
||||
"error" => Some(Token::Fail),
|
||||
|
@ -2009,7 +2010,7 @@ pub enum Error {
|
|||
#[diagnostic(code("illegal::module_name"))]
|
||||
#[diagnostic(help(r#"You cannot use keywords as part of a module path name. As a quick reminder, here's a list of all the keywords (and thus, of invalid module path names):
|
||||
|
||||
as, expect, check, const, else, fn, if, is, let, opaque, pub, test, todo, trace, type, use, when"#))]
|
||||
as, expect, check, const, else, fn, if, is, let, opaque, pub, test, todo, trace, emit, type, use, when"#))]
|
||||
KeywordInModuleName { name: String, keyword: String },
|
||||
|
||||
#[error("I realized you used '{}' as a module name, which is reserved (and not available).\n",
|
||||
|
|
|
@ -116,6 +116,13 @@ pub enum TypedExpr {
|
|||
text: Box<Self>,
|
||||
},
|
||||
|
||||
Emit {
|
||||
location: Span,
|
||||
tipo: Rc<Type>,
|
||||
then: Box<Self>,
|
||||
text: Box<Self>,
|
||||
},
|
||||
|
||||
When {
|
||||
location: Span,
|
||||
tipo: Rc<Type>,
|
||||
|
@ -196,6 +203,7 @@ impl TypedExpr {
|
|||
match self {
|
||||
Self::Var { constructor, .. } => constructor.tipo.clone(),
|
||||
Self::Trace { then, .. } => then.tipo(),
|
||||
Self::Emit { then, .. } => then.tipo(),
|
||||
Self::Fn { tipo, .. }
|
||||
| Self::UInt { tipo, .. }
|
||||
| Self::ErrorTerm { tipo, .. }
|
||||
|
@ -241,6 +249,7 @@ impl TypedExpr {
|
|||
TypedExpr::Fn { .. }
|
||||
| TypedExpr::UInt { .. }
|
||||
| TypedExpr::Trace { .. }
|
||||
| TypedExpr::Emit { .. }
|
||||
| TypedExpr::List { .. }
|
||||
| TypedExpr::Call { .. }
|
||||
| TypedExpr::When { .. }
|
||||
|
@ -283,6 +292,7 @@ impl TypedExpr {
|
|||
| Self::UInt { location, .. }
|
||||
| Self::Var { location, .. }
|
||||
| Self::Trace { location, .. }
|
||||
| Self::Emit { location, .. }
|
||||
| Self::ErrorTerm { location, .. }
|
||||
| Self::When { location, .. }
|
||||
| Self::Call { location, .. }
|
||||
|
@ -318,6 +328,7 @@ impl TypedExpr {
|
|||
Self::Fn { location, .. }
|
||||
| Self::UInt { location, .. }
|
||||
| Self::Trace { location, .. }
|
||||
| Self::Emit { location, .. }
|
||||
| Self::Var { location, .. }
|
||||
| Self::ErrorTerm { location, .. }
|
||||
| Self::When { location, .. }
|
||||
|
@ -360,6 +371,11 @@ impl TypedExpr {
|
|||
.find_node(byte_index)
|
||||
.or_else(|| then.find_node(byte_index))
|
||||
.or(Some(Located::Expression(self))),
|
||||
|
||||
TypedExpr::Emit { text, then, .. } => text
|
||||
.find_node(byte_index)
|
||||
.or_else(|| then.find_node(byte_index))
|
||||
.or(Some(Located::Expression(self))),
|
||||
|
||||
TypedExpr::Pipeline { expressions, .. } | TypedExpr::Sequence { expressions, .. } => {
|
||||
expressions.iter().find_map(|e| e.find_node(byte_index))
|
||||
|
@ -534,6 +550,12 @@ pub enum UntypedExpr {
|
|||
text: Box<Self>,
|
||||
},
|
||||
|
||||
Emit {
|
||||
location: Span,
|
||||
then: Box<Self>,
|
||||
text: Box<Self>,
|
||||
},
|
||||
|
||||
TraceIfFalse {
|
||||
location: Span,
|
||||
value: Box<Self>,
|
||||
|
@ -1245,6 +1267,7 @@ impl UntypedExpr {
|
|||
match self {
|
||||
Self::PipeLine { expressions, .. } => expressions.last().location(),
|
||||
Self::Trace { then, .. } => then.location(),
|
||||
Self::Emit { then, .. } => then.location(),
|
||||
Self::TraceIfFalse { location, .. }
|
||||
| Self::Fn { location, .. }
|
||||
| Self::Var { location, .. }
|
||||
|
@ -1284,7 +1307,7 @@ impl UntypedExpr {
|
|||
.map(|e| e.start_byte_index())
|
||||
.unwrap_or(location.start),
|
||||
Self::PipeLine { expressions, .. } => expressions.first().start_byte_index(),
|
||||
Self::Trace { location, .. } | Self::Assignment { location, .. } => location.start,
|
||||
Self::Trace { location, .. } | Self::Emit{ location, .. } | Self::Assignment { location, .. } => location.start,
|
||||
_ => self.location().start,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -639,7 +639,7 @@ impl<'comments> Formatter<'comments> {
|
|||
) -> Document<'a> {
|
||||
let args = wrap_args(args.iter().map(|e| (self.fn_arg(e), false))).group();
|
||||
let body = match body {
|
||||
UntypedExpr::Trace { .. } | UntypedExpr::When { .. } => {
|
||||
UntypedExpr::Trace { .. } | UntypedExpr::Emit { .. } | UntypedExpr::When { .. } => {
|
||||
self.expr(body, true).force_break()
|
||||
}
|
||||
_ => self.expr(body, true),
|
||||
|
@ -957,6 +957,10 @@ impl<'comments> Formatter<'comments> {
|
|||
kind, text, then, ..
|
||||
} => self.trace(kind, text, then),
|
||||
|
||||
UntypedExpr::Emit {
|
||||
text, then, ..
|
||||
} => self.emit(text, then),
|
||||
|
||||
UntypedExpr::When {
|
||||
subject, clauses, ..
|
||||
} => self.when(subject, clauses),
|
||||
|
@ -1045,6 +1049,25 @@ impl<'comments> Formatter<'comments> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn emit<'a>(
|
||||
&mut self,
|
||||
text: &'a UntypedExpr,
|
||||
then: &'a UntypedExpr,
|
||||
) -> Document<'a> {
|
||||
let body = "emit"
|
||||
.to_doc()
|
||||
.append(" ")
|
||||
.append(self.wrap_expr(text))
|
||||
.group();
|
||||
body
|
||||
.append(if self.pop_empty_lines(then.start_byte_index()) {
|
||||
lines(2)
|
||||
} else {
|
||||
line()
|
||||
})
|
||||
.append(self.expr(then, true))
|
||||
}
|
||||
|
||||
pub fn pattern_constructor<'a>(
|
||||
&mut self,
|
||||
name: &'a str,
|
||||
|
@ -1659,6 +1682,7 @@ impl<'comments> Formatter<'comments> {
|
|||
kind: TraceKind::Trace,
|
||||
..
|
||||
}
|
||||
| UntypedExpr::Emit { .. }
|
||||
| UntypedExpr::Sequence { .. }
|
||||
| UntypedExpr::Assignment { .. } => "{"
|
||||
.to_doc()
|
||||
|
@ -1701,6 +1725,7 @@ impl<'comments> Formatter<'comments> {
|
|||
kind: TraceKind::Trace,
|
||||
..
|
||||
}
|
||||
| UntypedExpr::Emit { .. }
|
||||
| UntypedExpr::Sequence { .. }
|
||||
| UntypedExpr::Assignment { .. } => " {"
|
||||
.to_doc()
|
||||
|
|
|
@ -530,6 +530,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
self.build(then, module_build_name, &[]),
|
||||
),
|
||||
|
||||
TypedExpr::Emit {
|
||||
tipo, then, text, ..
|
||||
} => AirTree::emit(
|
||||
self.build(text, module_build_name, &[]),
|
||||
tipo.clone(),
|
||||
self.build(then, module_build_name, &[]),
|
||||
),
|
||||
|
||||
TypedExpr::When {
|
||||
tipo,
|
||||
subject,
|
||||
|
@ -5310,6 +5318,15 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
Some(term)
|
||||
}
|
||||
Air::Emit { .. } => {
|
||||
let text = arg_stack.pop().unwrap();
|
||||
|
||||
let term = arg_stack.pop().unwrap();
|
||||
|
||||
let term = term.delayed_trace(text);
|
||||
|
||||
Some(term)
|
||||
}
|
||||
Air::ErrorTerm { validator, .. } => {
|
||||
if validator {
|
||||
Some(Term::Error.apply(Term::Error.force()))
|
||||
|
|
|
@ -198,6 +198,9 @@ pub enum Air {
|
|||
Trace {
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
Emit {
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
NoOp,
|
||||
FieldsEmpty,
|
||||
ListEmpty,
|
||||
|
|
|
@ -354,6 +354,11 @@ pub enum AirTree {
|
|||
msg: Box<AirTree>,
|
||||
then: Box<AirTree>,
|
||||
},
|
||||
Emit {
|
||||
tipo: Rc<Type>,
|
||||
msg: Box<AirTree>,
|
||||
then: Box<AirTree>,
|
||||
},
|
||||
// End Expressions
|
||||
}
|
||||
|
||||
|
@ -830,6 +835,13 @@ impl AirTree {
|
|||
then: then.into(),
|
||||
}
|
||||
}
|
||||
pub fn emit(msg: AirTree, tipo: Rc<Type>, then: AirTree) -> AirTree {
|
||||
AirTree::Emit {
|
||||
tipo,
|
||||
msg: msg.into(),
|
||||
then: then.into(),
|
||||
}
|
||||
}
|
||||
pub fn no_op(then: AirTree) -> AirTree {
|
||||
AirTree::NoOp { then: then.into() }
|
||||
}
|
||||
|
@ -1379,6 +1391,11 @@ impl AirTree {
|
|||
msg.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
}
|
||||
AirTree::Emit { tipo, msg, then } => {
|
||||
air_vec.push(Air::Emit { tipo: tipo.clone() });
|
||||
msg.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1400,7 +1417,8 @@ impl AirTree {
|
|||
| AirTree::Constr { tipo, .. }
|
||||
| AirTree::RecordUpdate { tipo, .. }
|
||||
| AirTree::ErrorTerm { tipo, .. }
|
||||
| AirTree::Trace { tipo, .. } => tipo.clone(),
|
||||
| AirTree::Trace { tipo, .. }
|
||||
| AirTree::Emit { tipo, .. } => tipo.clone(),
|
||||
AirTree::Void => void(),
|
||||
AirTree::Var { constructor, .. } => constructor.tipo.clone(),
|
||||
AirTree::Fn { func_body, .. } => func_body.return_type(),
|
||||
|
@ -1456,7 +1474,8 @@ impl AirTree {
|
|||
| AirTree::If { tipo, .. }
|
||||
| AirTree::Constr { tipo, .. }
|
||||
| AirTree::ErrorTerm { tipo, .. }
|
||||
| AirTree::Trace { tipo, .. } => vec![tipo],
|
||||
| AirTree::Trace { tipo, .. }
|
||||
| AirTree::Emit { tipo, .. } => vec![tipo],
|
||||
AirTree::Var { constructor, .. } => {
|
||||
vec![constructor.tipo.borrow_mut()]
|
||||
}
|
||||
|
@ -1940,6 +1959,23 @@ impl AirTree {
|
|||
apply_with_func_last,
|
||||
);
|
||||
}
|
||||
AirTree::Emit { msg, then, .. } => {
|
||||
msg.do_traverse_tree_with(
|
||||
tree_path,
|
||||
current_depth + 1,
|
||||
index_count.next_number(),
|
||||
with,
|
||||
apply_with_func_last,
|
||||
);
|
||||
|
||||
then.do_traverse_tree_with(
|
||||
tree_path,
|
||||
current_depth + 1,
|
||||
index_count.next_number(),
|
||||
with,
|
||||
apply_with_func_last,
|
||||
);
|
||||
}
|
||||
AirTree::DefineFunc {
|
||||
func_body, then, ..
|
||||
} => {
|
||||
|
@ -2284,6 +2320,15 @@ impl AirTree {
|
|||
panic!("Tree Path index outside tree children nodes")
|
||||
}
|
||||
}
|
||||
AirTree::Emit { msg, then, .. } => {
|
||||
if *index == 0 {
|
||||
msg.as_mut().do_find_air_tree_node(tree_path_iter)
|
||||
} else if *index == 1 {
|
||||
then.as_mut().do_find_air_tree_node(tree_path_iter)
|
||||
} else {
|
||||
panic!("Tree Path index outside tree children nodes")
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
panic!("A tree node with no children was encountered with a longer tree path.")
|
||||
}
|
||||
|
|
|
@ -36,6 +36,14 @@ pub fn parser<'a>(
|
|||
then: Box::new(then_.unwrap_or_else(|| UntypedExpr::todo(None, span))),
|
||||
text: Box::new(text),
|
||||
}),
|
||||
just(Token::Emit)
|
||||
.ignore_then(choice((string::hybrid(), expression.clone())))
|
||||
.then(sequence.clone().or_not())
|
||||
.map_with_span(|(text, then_), span| UntypedExpr::Emit {
|
||||
location: span,
|
||||
then: Box::new(then_.unwrap_or_else(|| UntypedExpr::todo(None, span))),
|
||||
text: Box::new(text),
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
@ -220,6 +220,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
|
|||
|
||||
let keyword = text::ident().map(|s: String| match s.as_str() {
|
||||
"trace" => Token::Trace,
|
||||
"emit" => Token::Emit,
|
||||
// TODO: remove this in a future release
|
||||
"error" => Token::Fail,
|
||||
"fail" => Token::Fail,
|
||||
|
|
|
@ -89,6 +89,7 @@ pub enum Token {
|
|||
Type,
|
||||
When,
|
||||
Trace,
|
||||
Emit,
|
||||
Validator,
|
||||
Via,
|
||||
}
|
||||
|
@ -175,6 +176,7 @@ impl fmt::Display for Token {
|
|||
Token::Pub => "pub",
|
||||
Token::Todo => "todo",
|
||||
Token::Trace => "trace",
|
||||
Token::Emit => "emit",
|
||||
Token::Type => "type",
|
||||
Token::Test => "test",
|
||||
Token::Fail => "fail",
|
||||
|
|
|
@ -281,6 +281,22 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
kind,
|
||||
} => self.infer_trace(kind, *then, location, *text),
|
||||
|
||||
UntypedExpr::Emit {
|
||||
location,
|
||||
then,
|
||||
text,
|
||||
} => {
|
||||
let text = self.infer(*text)?;
|
||||
self.unify(string(), text.tipo(), text.location(), false)?;
|
||||
let then = self.infer(*then)?;
|
||||
Ok(TypedExpr::Emit {
|
||||
location,
|
||||
tipo: then.tipo(),
|
||||
then: Box::new(then),
|
||||
text: Box::new(text),
|
||||
})
|
||||
}
|
||||
|
||||
UntypedExpr::When {
|
||||
location,
|
||||
subject,
|
||||
|
@ -2324,7 +2340,7 @@ fn assert_no_assignment(expr: &UntypedExpr) -> Result<(), Error> {
|
|||
location: expr.location(),
|
||||
expr: *value.clone(),
|
||||
}),
|
||||
UntypedExpr::Trace { then, .. } => assert_no_assignment(then),
|
||||
UntypedExpr::Trace { then, .. } | UntypedExpr::Emit { then, .. } => assert_no_assignment(then),
|
||||
UntypedExpr::Fn { .. }
|
||||
| UntypedExpr::BinOp { .. }
|
||||
| UntypedExpr::ByteArray { .. }
|
||||
|
|
|
@ -1085,6 +1085,7 @@ impl TryFrom<TypedExpr> for Assertion<TypedExpr> {
|
|||
}
|
||||
|
||||
TypedExpr::Trace { then, .. } => (*then).try_into(),
|
||||
TypedExpr::Emit { then, .. } => (*then).try_into(),
|
||||
|
||||
TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => {
|
||||
if let Ok(Assertion {
|
||||
|
|
Loading…
Reference in New Issue