Skip to content

Commit

Permalink
Print builtin
Browse files Browse the repository at this point in the history
  • Loading branch information
chriseth committed Jan 24, 2024
1 parent 1b24ac3 commit 8d8b7cf
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 4 deletions.
23 changes: 23 additions & 0 deletions parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,29 @@ pub fn parse_module<'a, T: FieldElement>(
.map_err(|err| handle_parse_error(err, file_name, input))
}

/// Parse an escaped string - used in the grammar.
pub fn unescape_string(s: &str) -> String {
assert!(s.len() >= 2);
assert!(s.starts_with('"') && s.ends_with('"'));
let mut chars = s[1..s.len() - 1].chars();
let mut result: String = Default::default();
while let Some(c) = chars.next() {
result.push(if c == '\\' {
match chars.next().unwrap() {
'n' => '\n',
'r' => '\r',
't' => '\t',
'b' => 8 as char,
'f' => 12 as char,
other => other,
}
} else {
c
})
}
result
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
4 changes: 2 additions & 2 deletions parser/src/powdr.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::str::FromStr;
use powdr_ast::parsed::{*, asm::*};
use powdr_number::{AbstractNumberType, FieldElement};
use num_traits::Num;
use crate::ParserContext;
use crate::{ParserContext, unescape_string};

grammar<T>(ctx: &ParserContext) where T: FieldElement;

Expand Down Expand Up @@ -544,7 +544,7 @@ IfExpression: Box<Expression<T>> = {


StringLiteral: String = {
r#""[^"]*""# => <>[1..<>.len() - 1].to_string()
r#""[^\\"\n\r]*(\\[tnfbrx'"\\0-9][^\\"\n\r]*)*""# => unescape_string(<>)
}

Identifier: String = {
Expand Down
23 changes: 21 additions & 2 deletions pil-analyzer/src/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,22 @@ impl<'a, T: FieldElement, C: Custom> Value<'a, T, C> {
}
}

const BUILTINS: [(&str, BuiltinFunction); 2] = [
const BUILTINS: [(&str, BuiltinFunction); 3] = [
("std::array::len", BuiltinFunction::ArrayLen),
("std::check::panic", BuiltinFunction::Panic),
("std::debug::print", BuiltinFunction::Print),
];

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum BuiltinFunction {
/// std::array::len: [_] -> int, returns the length of an array
ArrayLen,
/// std::check::panic: string -> !, fails evaluation and uses its parameter for error reporting.
/// Returns the empty tuple.
/// Does not return.
Panic,
/// std::debug::print: string -> [], prints its argument on stdout.
/// Returns an empty array.
Print,
}

pub trait Custom: Display + fmt::Debug + Clone + PartialEq {
Expand Down Expand Up @@ -326,6 +330,10 @@ mod internal {
l.extend(std::mem::take(r));
Value::Array(std::mem::take(l))
}
(Value::String(l), BinaryOperator::Add, Value::String(r)) => {
l.push_str(r);
Value::String(std::mem::take(l))
}
(Value::Number(l), _, Value::Number(r)) => {
Value::Number(evaluate_binary_operation(*l, *op, *r))
}
Expand Down Expand Up @@ -430,13 +438,15 @@ mod internal {
})
}

#[allow(clippy::print_stdout)]
pub fn evaluate_builtin_function<T: FieldElement, C: Custom>(
b: BuiltinFunction,
mut arguments: Vec<Rc<Value<'_, T, C>>>,
) -> Result<Value<'_, T, C>, EvalError> {
let params = match b {
BuiltinFunction::ArrayLen => 1,
BuiltinFunction::Panic => 1,
BuiltinFunction::Print => 1,
};

if arguments.len() != params {
Expand All @@ -461,6 +471,15 @@ mod internal {
};
Err(EvalError::FailedAssertion(msg))?
}
BuiltinFunction::Print => {
let msg = match arguments.pop().unwrap().as_ref() {
Value::String(msg) => msg.clone(),
// As long as we do not yet have types, we just format any argument.
x => x.to_string(),
};
print!("{msg}");
Value::Array(Default::default())
}
})
}
}
Expand Down
7 changes: 7 additions & 0 deletions std/debug.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// This is a built-in function taking a string argument and printing it on stdout
/// when evaluated.
/// It returns an empty array so that it can be used at constraint level.
/// This symbol is not an empty array, the actual semantics are overridden.
let print = [];

let println = |msg| print(msg + "\n");
1 change: 1 addition & 0 deletions std/mod.asm
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod array;
mod binary;
mod check;
mod debug;
mod hash;
mod shift;
mod split;
Expand Down

0 comments on commit 8d8b7cf

Please sign in to comment.