mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-21 18:10:42 -04:00
FEATURE: Add a TRACE pragma for assitance debugging ucg files.
This commit is contained in:
parent
c8e48bd9f4
commit
ec756636b0
@ -660,4 +660,25 @@ fail "Oh No This was not what we wanted!";
|
||||
fail "Expected foo but got @" % ("bar");
|
||||
```
|
||||
|
||||
Trace Expression
|
||||
----------------
|
||||
|
||||
UCG has a debugging expression that can be helpful to trace values while developing called the trace expression.
|
||||
|
||||
Trace expression are any valid expression preceded by the `TRACE` keyword. Trace
|
||||
expression return the result of the expression unchanged but they also output a
|
||||
trace statement to stderr printing the result of the expression as well as the
|
||||
file, line and column where the expression was.
|
||||
|
||||
```
|
||||
let mk_list = func(a, b) => TRACE [a, b];
|
||||
mk_list(1, 2);
|
||||
```
|
||||
|
||||
This will output a line to stderr something like the below:
|
||||
|
||||
TRACE: [1, 2] at file: <file name> line: 1 column: 29
|
||||
|
||||
This is helpful when developing shared modules or ucg libraries.
|
||||
|
||||
Next: <a href="/reference/statements">Statements</a>
|
@ -57,6 +57,7 @@ mod_keyword: "mod" ;
|
||||
out_keyword: "out" ;
|
||||
assert_keyword: "assert" ;
|
||||
fail_keyword: "fail" ;
|
||||
trace_keyword: "TRACE" ;
|
||||
null_keyword: "NULL" ;
|
||||
in_keyword: "in" ;
|
||||
is_keyword: "in" ;
|
||||
@ -176,6 +177,12 @@ fail_expr: fail_keyword, (str | format_expr) ;
|
||||
not_expr: not_keyword, expr ;
|
||||
```
|
||||
|
||||
#### Not Expression
|
||||
|
||||
```
|
||||
trace_expr: trace_keyword, expr ;
|
||||
```
|
||||
|
||||
#### Non Operator Expression
|
||||
|
||||
```
|
||||
@ -185,6 +192,8 @@ non_operator_expr: literal
|
||||
| funcdef
|
||||
| module_def
|
||||
| fail_expr
|
||||
| not_expr
|
||||
| trace_expr
|
||||
| format_expr
|
||||
| range_expr
|
||||
| include_expr
|
||||
|
@ -84,6 +84,15 @@ impl<'a> From<&'a Position> for Position {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Position {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
if let Some(ref file) = self.file {
|
||||
write!(f, "file: {}", file.to_string_lossy().to_string())?;
|
||||
}
|
||||
write!(f, "line: {} column: {}", self.line, self.column)
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the types of tokens in UCG syntax.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
|
||||
pub enum TokenType {
|
||||
@ -626,6 +635,12 @@ pub struct NotDef {
|
||||
pub expr: Box<Expression>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct DebugDef {
|
||||
pub pos: Position,
|
||||
pub expr: Box<Expression>,
|
||||
}
|
||||
|
||||
/// Encodes a ucg expression. Expressions compute a value from.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Expression {
|
||||
@ -651,6 +666,8 @@ pub enum Expression {
|
||||
|
||||
// Declarative failure expressions
|
||||
Fail(FailDef),
|
||||
// Debugging assistance
|
||||
Debug(DebugDef),
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
@ -672,6 +689,7 @@ impl Expression {
|
||||
&Expression::Import(ref def) => &def.pos,
|
||||
&Expression::Fail(ref def) => &def.pos,
|
||||
&Expression::Not(ref def) => &def.pos,
|
||||
&Expression::Debug(ref def) => &def.pos,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -724,6 +742,9 @@ impl fmt::Display for Expression {
|
||||
&Expression::Not(ref def) => {
|
||||
write!(w, "!{}", def.expr)?;
|
||||
}
|
||||
&Expression::Debug(ref def) => {
|
||||
write!(w, "!{}", def.expr)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -129,6 +129,9 @@ impl<'a> AstWalker<'a> {
|
||||
Expression::Not(ref mut def) => {
|
||||
self.walk_expression(def.expr.as_mut());
|
||||
}
|
||||
Expression::Debug(ref mut def) => {
|
||||
self.walk_expression(&mut def.expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1944,8 +1944,8 @@ impl<'a> FileBuilder<'a> {
|
||||
&Expression::Include(ref def) => self.eval_include(def),
|
||||
&Expression::Import(ref def) => self.eval_import(def),
|
||||
&Expression::Fail(ref def) => {
|
||||
let err = self.eval_expr(&def.message, scope)?;
|
||||
return if let Val::Str(ref s) = err.as_ref() {
|
||||
let val = self.eval_expr(&def.message, scope)?;
|
||||
return if let Val::Str(ref s) = val.as_ref() {
|
||||
Err(error::BuildError::with_pos(
|
||||
s.clone(),
|
||||
error::ErrorType::UserDefined,
|
||||
@ -1964,6 +1964,13 @@ impl<'a> FileBuilder<'a> {
|
||||
.to_boxed())
|
||||
};
|
||||
}
|
||||
&Expression::Debug(ref def) => {
|
||||
let val = self.eval_expr(&def.expr, scope);
|
||||
if let Ok(ref val) = val {
|
||||
eprintln!("TRACE: {} at {}", val, def.pos);
|
||||
}
|
||||
val
|
||||
}
|
||||
&Expression::Not(ref def) => {
|
||||
let val = self.eval_expr(&def.expr, scope)?;
|
||||
return if let Val::Boolean(b) = val.as_ref() {
|
||||
|
@ -714,6 +714,19 @@ make_fn!(
|
||||
)
|
||||
);
|
||||
|
||||
make_fn!(
|
||||
trace_expression<SliceIter<Token>, Expression>,
|
||||
do_each!(
|
||||
pos => pos,
|
||||
_ => word!("TRACE"),
|
||||
expr => must!(wrap_err!(expression, "Expected failure message")),
|
||||
(Expression::Debug(DebugDef{
|
||||
pos: pos,
|
||||
expr: Box::new(expr),
|
||||
}))
|
||||
)
|
||||
);
|
||||
|
||||
make_fn!(
|
||||
not_expression<SliceIter<Token>, Expression>,
|
||||
do_each!(
|
||||
@ -745,6 +758,7 @@ make_fn!(
|
||||
trace_parse!(func_op_expression),
|
||||
trace_parse!(func_expression),
|
||||
trace_parse!(import_expression),
|
||||
trace_parse!(trace_expression),
|
||||
trace_parse!(not_expression),
|
||||
trace_parse!(fail_expression),
|
||||
trace_parse!(module_expression),
|
||||
|
@ -286,6 +286,10 @@ make_fn!(nottok<OffsetStrIter, Token>,
|
||||
do_text_token_tok!(TokenType::BAREWORD, "not", WS)
|
||||
);
|
||||
|
||||
make_fn!(tracetok<OffsetStrIter, Token>,
|
||||
do_text_token_tok!(TokenType::BAREWORD, "TRACE", WS)
|
||||
);
|
||||
|
||||
make_fn!(failtok<OffsetStrIter, Token>,
|
||||
do_text_token_tok!(TokenType::BAREWORD, "fail", WS)
|
||||
);
|
||||
@ -432,6 +436,7 @@ fn token<'a>(input: OffsetStrIter<'a>) -> Result<OffsetStrIter<'a>, Token> {
|
||||
selecttok,
|
||||
asserttok,
|
||||
failtok,
|
||||
tracetok,
|
||||
functok,
|
||||
moduletok,
|
||||
importtok,
|
||||
|
Loading…
x
Reference in New Issue
Block a user