New syntax 💎
- Everything everywhere! - Blocks with curly braces: {} - Templates with brackets: [] - Function templates with hashtag: `#[f]` - Headings with equals sign: `= Introduction`
This commit is contained in:
parent
ac24075469
commit
89eb8bae49
@ -8,7 +8,7 @@ use super::{Args, Eval, EvalContext};
|
|||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::geom::{Angle, Length, Linear, Relative};
|
use crate::geom::{Angle, Length, Linear, Relative};
|
||||||
use crate::pretty::{pretty, Pretty, Printer};
|
use crate::pretty::{pretty, Pretty, Printer};
|
||||||
use crate::syntax::{Spanned, Tree, WithSpan};
|
use crate::syntax::{pretty_template, Spanned, Tree, WithSpan};
|
||||||
|
|
||||||
/// A computational value.
|
/// A computational value.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -121,11 +121,7 @@ impl Pretty for Value {
|
|||||||
Value::Str(v) => write!(p, "{:?}", v).unwrap(),
|
Value::Str(v) => write!(p, "{:?}", v).unwrap(),
|
||||||
Value::Array(v) => v.pretty(p),
|
Value::Array(v) => v.pretty(p),
|
||||||
Value::Dict(v) => v.pretty(p),
|
Value::Dict(v) => v.pretty(p),
|
||||||
Value::Template(v) => {
|
Value::Template(v) => pretty_template(v, p),
|
||||||
p.push_str("[");
|
|
||||||
v.pretty(p);
|
|
||||||
p.push_str("]");
|
|
||||||
}
|
|
||||||
Value::Func(v) => v.pretty(p),
|
Value::Func(v) => v.pretty(p),
|
||||||
Value::Any(v) => v.pretty(p),
|
Value::Any(v) => v.pretty(p),
|
||||||
Value::Error => p.push_str("(error)"),
|
Value::Error => p.push_str("(error)"),
|
||||||
@ -537,8 +533,8 @@ mod tests {
|
|||||||
// Dictionary.
|
// Dictionary.
|
||||||
let mut dict = BTreeMap::new();
|
let mut dict = BTreeMap::new();
|
||||||
dict.insert("one".into(), Value::Int(1));
|
dict.insert("one".into(), Value::Int(1));
|
||||||
dict.insert("two".into(), Value::Template(parse("[f]").output));
|
dict.insert("two".into(), Value::Template(parse("#[f]").output));
|
||||||
test_pretty(BTreeMap::new(), "(:)");
|
test_pretty(BTreeMap::new(), "(:)");
|
||||||
test_pretty(dict, "(one: 1, two: [[f]])");
|
test_pretty(dict, "(one: 1, two: #[f])");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
116
src/parse/mod.rs
116
src/parse/mod.rs
@ -45,38 +45,33 @@ fn tree(p: &mut Parser) -> Tree {
|
|||||||
fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
|
fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
|
||||||
let token = p.peek()?;
|
let token = p.peek()?;
|
||||||
let node = match token {
|
let node = match token {
|
||||||
// Bracket call.
|
// Whitespace.
|
||||||
Token::LeftBracket => {
|
Token::Space(newlines) => {
|
||||||
return Some(Node::Expr(bracket_call(p)?));
|
*at_start |= newlines > 0;
|
||||||
|
if newlines < 2 { Node::Space } else { Node::Parbreak }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code block.
|
// Text.
|
||||||
Token::LeftBrace => {
|
Token::Text(text) => Node::Text(text.into()),
|
||||||
return Some(Node::Expr(block(p, false)?));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Markup.
|
// Markup.
|
||||||
Token::Star => Node::Strong,
|
Token::Star => Node::Strong,
|
||||||
Token::Underscore => Node::Emph,
|
Token::Underscore => Node::Emph,
|
||||||
Token::Tilde => Node::Text("\u{00A0}".into()),
|
Token::Eq => {
|
||||||
Token::Hash => {
|
|
||||||
if *at_start {
|
if *at_start {
|
||||||
return Some(Node::Heading(heading(p)));
|
return Some(Node::Heading(heading(p)));
|
||||||
} else {
|
} else {
|
||||||
Node::Text(p.get(p.peek_span()).into())
|
Node::Text(p.get(p.peek_span()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Token::Tilde => Node::Text("\u{00A0}".into()),
|
||||||
Token::Backslash => Node::Linebreak,
|
Token::Backslash => Node::Linebreak,
|
||||||
Token::Space(newlines) => {
|
|
||||||
*at_start |= newlines > 0;
|
|
||||||
if newlines < 2 { Node::Space } else { Node::Parbreak }
|
|
||||||
}
|
|
||||||
Token::Text(text) => Node::Text(text.into()),
|
|
||||||
Token::Raw(t) => Node::Raw(raw(p, t)),
|
Token::Raw(t) => Node::Raw(raw(p, t)),
|
||||||
Token::UnicodeEscape(t) => Node::Text(unicode_escape(p, t)),
|
Token::UnicodeEscape(t) => Node::Text(unicode_escape(p, t)),
|
||||||
|
|
||||||
// Keywords.
|
// Keywords.
|
||||||
Token::Let | Token::If | Token::For => {
|
Token::Let | Token::If | Token::For => {
|
||||||
|
*at_start = false;
|
||||||
let stmt = token == Token::Let;
|
let stmt = token == Token::Let;
|
||||||
let group = if stmt { Group::Stmt } else { Group::Expr };
|
let group = if stmt { Group::Stmt } else { Group::Expr };
|
||||||
|
|
||||||
@ -92,6 +87,24 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
|
|||||||
return expr.map(Node::Expr);
|
return expr.map(Node::Expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Block.
|
||||||
|
Token::LeftBrace => {
|
||||||
|
*at_start = false;
|
||||||
|
return Some(Node::Expr(block(p, false)?));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template.
|
||||||
|
Token::LeftBracket => {
|
||||||
|
*at_start = false;
|
||||||
|
return Some(Node::Expr(template(p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function template.
|
||||||
|
Token::HashBracket => {
|
||||||
|
*at_start = false;
|
||||||
|
return Some(Node::Expr(bracket_call(p)?));
|
||||||
|
}
|
||||||
|
|
||||||
// Comments.
|
// Comments.
|
||||||
Token::LineComment(_) | Token::BlockComment(_) => {
|
Token::LineComment(_) | Token::BlockComment(_) => {
|
||||||
p.eat();
|
p.eat();
|
||||||
@ -99,6 +112,7 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
*at_start = false;
|
||||||
p.unexpected();
|
p.unexpected();
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -109,12 +123,12 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
|
|||||||
|
|
||||||
/// Parse a heading.
|
/// Parse a heading.
|
||||||
fn heading(p: &mut Parser) -> NodeHeading {
|
fn heading(p: &mut Parser) -> NodeHeading {
|
||||||
// Count hashtags.
|
// Count depth.
|
||||||
let mut level = p.span(|p| {
|
let mut level = p.span(|p| {
|
||||||
p.assert(Token::Hash);
|
p.assert(&[Token::Eq]);
|
||||||
|
|
||||||
let mut level = 0u8;
|
let mut level = 0u8;
|
||||||
while p.eat_if(Token::Hash) {
|
while p.eat_if(Token::Eq) {
|
||||||
level = level.saturating_add(1);
|
level = level.saturating_add(1);
|
||||||
}
|
}
|
||||||
level
|
level
|
||||||
@ -278,33 +292,6 @@ fn expr_with(p: &mut Parser, min_prec: usize) -> Option<Expr> {
|
|||||||
/// Parse a primary expression.
|
/// Parse a primary expression.
|
||||||
fn primary(p: &mut Parser) -> Option<Expr> {
|
fn primary(p: &mut Parser) -> Option<Expr> {
|
||||||
let expr = match p.peek() {
|
let expr = match p.peek() {
|
||||||
// Template.
|
|
||||||
Some(Token::LeftBracket) => {
|
|
||||||
return Some(template(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nested block.
|
|
||||||
Some(Token::LeftBrace) => {
|
|
||||||
return block(p, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dictionary or just a parenthesized expression.
|
|
||||||
Some(Token::LeftParen) => {
|
|
||||||
return Some(parenthesized(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function or just ident.
|
|
||||||
Some(Token::Ident(id)) => {
|
|
||||||
p.eat();
|
|
||||||
let ident = Ident(id.into());
|
|
||||||
if p.peek() == Some(Token::LeftParen) {
|
|
||||||
let name = ident.with_span(p.peek_span());
|
|
||||||
return Some(paren_call(p, name));
|
|
||||||
} else {
|
|
||||||
return Some(Expr::Ident(ident));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic values.
|
// Basic values.
|
||||||
Some(Token::None) => Expr::None,
|
Some(Token::None) => Expr::None,
|
||||||
Some(Token::Bool(b)) => Expr::Bool(b),
|
Some(Token::Bool(b)) => Expr::Bool(b),
|
||||||
@ -316,12 +303,45 @@ fn primary(p: &mut Parser) -> Option<Expr> {
|
|||||||
Some(Token::Color(color)) => Expr::Color(color),
|
Some(Token::Color(color)) => Expr::Color(color),
|
||||||
Some(Token::Str(token)) => Expr::Str(string(p, token)),
|
Some(Token::Str(token)) => Expr::Str(string(p, token)),
|
||||||
|
|
||||||
|
// Function or identifier.
|
||||||
|
Some(Token::Ident(id)) => {
|
||||||
|
p.eat();
|
||||||
|
let ident = Ident(id.into());
|
||||||
|
if p.peek() == Some(Token::LeftParen) {
|
||||||
|
let name = ident.with_span(p.peek_span());
|
||||||
|
return Some(paren_call(p, name));
|
||||||
|
} else {
|
||||||
|
return Some(Expr::Ident(ident));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Keywords.
|
// Keywords.
|
||||||
Some(Token::Let) => return expr_let(p),
|
Some(Token::Let) => return expr_let(p),
|
||||||
Some(Token::If) => return expr_if(p),
|
Some(Token::If) => return expr_if(p),
|
||||||
Some(Token::For) => return expr_for(p),
|
Some(Token::For) => return expr_for(p),
|
||||||
|
|
||||||
// No value.
|
// Block.
|
||||||
|
Some(Token::LeftBrace) => {
|
||||||
|
return block(p, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template.
|
||||||
|
Some(Token::LeftBracket) => {
|
||||||
|
return Some(template(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function template.
|
||||||
|
Some(Token::HashBracket) => {
|
||||||
|
let call = p.span_if(bracket_call)?.map(Node::Expr);
|
||||||
|
return Some(Expr::Template(vec![call]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array, dictionary or parenthesized expression.
|
||||||
|
Some(Token::LeftParen) => {
|
||||||
|
return Some(parenthesized(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing.
|
||||||
_ => {
|
_ => {
|
||||||
p.expected("expression");
|
p.expected("expression");
|
||||||
return None;
|
return None;
|
||||||
@ -380,7 +400,7 @@ fn string(p: &mut Parser, token: TokenStr) -> String {
|
|||||||
|
|
||||||
/// Parse a let expression.
|
/// Parse a let expression.
|
||||||
fn expr_let(p: &mut Parser) -> Option<Expr> {
|
fn expr_let(p: &mut Parser) -> Option<Expr> {
|
||||||
p.assert(Token::Let);
|
p.assert(&[Token::Let]);
|
||||||
|
|
||||||
let mut expr_let = None;
|
let mut expr_let = None;
|
||||||
if let Some(pat) = p.span_if(ident) {
|
if let Some(pat) = p.span_if(ident) {
|
||||||
@ -397,7 +417,7 @@ fn expr_let(p: &mut Parser) -> Option<Expr> {
|
|||||||
|
|
||||||
/// Parse an if expresion.
|
/// Parse an if expresion.
|
||||||
fn expr_if(p: &mut Parser) -> Option<Expr> {
|
fn expr_if(p: &mut Parser) -> Option<Expr> {
|
||||||
p.assert(Token::If);
|
p.assert(&[Token::If]);
|
||||||
|
|
||||||
let mut expr_if = None;
|
let mut expr_if = None;
|
||||||
if let Some(condition) = p.span_if(expr) {
|
if let Some(condition) = p.span_if(expr) {
|
||||||
@ -420,7 +440,7 @@ fn expr_if(p: &mut Parser) -> Option<Expr> {
|
|||||||
|
|
||||||
/// Parse a for expression.
|
/// Parse a for expression.
|
||||||
fn expr_for(p: &mut Parser) -> Option<Expr> {
|
fn expr_for(p: &mut Parser) -> Option<Expr> {
|
||||||
p.assert(Token::For);
|
p.assert(&[Token::For]);
|
||||||
|
|
||||||
let mut expr_for = None;
|
let mut expr_for = None;
|
||||||
if let Some(pat) = p.span_if(for_pattern) {
|
if let Some(pat) = p.span_if(for_pattern) {
|
||||||
|
@ -105,9 +105,9 @@ impl<'s> Parser<'s> {
|
|||||||
self.repeek();
|
self.repeek();
|
||||||
|
|
||||||
match group {
|
match group {
|
||||||
Group::Paren => self.assert(Token::LeftParen),
|
Group::Paren => self.assert(&[Token::LeftParen]),
|
||||||
Group::Bracket => self.assert(Token::LeftBracket),
|
Group::Bracket => self.assert(&[Token::HashBracket, Token::LeftBracket]),
|
||||||
Group::Brace => self.assert(Token::LeftBrace),
|
Group::Brace => self.assert(&[Token::LeftBrace]),
|
||||||
Group::Subheader => {}
|
Group::Subheader => {}
|
||||||
Group::Stmt => {}
|
Group::Stmt => {}
|
||||||
Group::Expr => {}
|
Group::Expr => {}
|
||||||
@ -210,10 +210,10 @@ impl<'s> Parser<'s> {
|
|||||||
eaten
|
eaten
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume the next token, debug-asserting that it is the given one.
|
/// Consume the next token, debug-asserting that it is one of the given ones.
|
||||||
pub fn assert(&mut self, t: Token) {
|
pub fn assert(&mut self, ts: &[Token]) {
|
||||||
let next = self.eat();
|
let next = self.eat();
|
||||||
debug_assert_eq!(next, Some(t));
|
debug_assert!(next.map_or(false, |n| ts.contains(&n)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Skip whitespace and comment tokens.
|
/// Skip whitespace and comment tokens.
|
||||||
|
@ -67,12 +67,15 @@ impl<'s> Iterator for Tokens<'s> {
|
|||||||
loop {
|
loop {
|
||||||
// Common elements.
|
// Common elements.
|
||||||
return Some(match c {
|
return Some(match c {
|
||||||
// Functions, blocks and terminators.
|
// Blocks and templates.
|
||||||
'[' => Token::LeftBracket,
|
'[' => Token::LeftBracket,
|
||||||
']' => Token::RightBracket,
|
']' => Token::RightBracket,
|
||||||
'{' => Token::LeftBrace,
|
'{' => Token::LeftBrace,
|
||||||
'}' => Token::RightBrace,
|
'}' => Token::RightBrace,
|
||||||
|
|
||||||
|
// Keywords, function templates, colors.
|
||||||
|
'#' => self.hash(start),
|
||||||
|
|
||||||
// Whitespace.
|
// Whitespace.
|
||||||
c if c.is_whitespace() => self.whitespace(c),
|
c if c.is_whitespace() => self.whitespace(c),
|
||||||
|
|
||||||
@ -90,8 +93,8 @@ impl<'s> Iterator for Tokens<'s> {
|
|||||||
// Markup.
|
// Markup.
|
||||||
'*' => Token::Star,
|
'*' => Token::Star,
|
||||||
'_' => Token::Underscore,
|
'_' => Token::Underscore,
|
||||||
|
'=' => Token::Eq,
|
||||||
'~' => Token::Tilde,
|
'~' => Token::Tilde,
|
||||||
'#' => self.hash(start),
|
|
||||||
'`' => self.raw(),
|
'`' => self.raw(),
|
||||||
'$' => self.math(),
|
'$' => self.math(),
|
||||||
'\\' => self.backslash(),
|
'\\' => self.backslash(),
|
||||||
@ -140,8 +143,7 @@ impl<'s> Iterator for Tokens<'s> {
|
|||||||
self.number(start, c)
|
self.number(start, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hex values and strings.
|
// Strings.
|
||||||
'#' => self.hex(start),
|
|
||||||
'"' => self.string(),
|
'"' => self.string(),
|
||||||
|
|
||||||
_ => Token::Invalid(self.s.eaten_from(start)),
|
_ => Token::Invalid(self.s.eaten_from(start)),
|
||||||
@ -151,6 +153,27 @@ impl<'s> Iterator for Tokens<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Tokens<'s> {
|
impl<'s> Tokens<'s> {
|
||||||
|
fn hash(&mut self, start: usize) -> Token<'s> {
|
||||||
|
if self.s.eat_if('[') {
|
||||||
|
return Token::HashBracket;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.s.eat_while(is_id_continue);
|
||||||
|
let read = self.s.eaten_from(start);
|
||||||
|
|
||||||
|
if let Some(keyword) = keyword(read) {
|
||||||
|
return keyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.mode == TokenMode::Code {
|
||||||
|
if let Ok(color) = RgbaColor::from_str(read) {
|
||||||
|
return Token::Color(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Token::Invalid(read)
|
||||||
|
}
|
||||||
|
|
||||||
fn whitespace(&mut self, first: char) -> Token<'s> {
|
fn whitespace(&mut self, first: char) -> Token<'s> {
|
||||||
// Fast path for just a single space
|
// Fast path for just a single space
|
||||||
if first == ' ' && !self.s.check(|c| c.is_whitespace()) {
|
if first == ' ' && !self.s.check(|c| c.is_whitespace()) {
|
||||||
@ -182,10 +205,10 @@ impl<'s> Tokens<'s> {
|
|||||||
c if c.is_whitespace() => true,
|
c if c.is_whitespace() => true,
|
||||||
// Comments.
|
// Comments.
|
||||||
'/' if self.s.check(|c| c == '/' || c == '*') => true,
|
'/' if self.s.check(|c| c == '/' || c == '*') => true,
|
||||||
// Parenthesis.
|
// Parenthesis and hashtag.
|
||||||
'[' | ']' | '{' | '}' => true,
|
'[' | ']' | '{' | '}' | '#' => true,
|
||||||
// Markup.
|
// Markup.
|
||||||
'*' | '_' | '#' | '~' | '`' | '$' => true,
|
'*' | '_' | '=' | '~' | '`' | '$' => true,
|
||||||
// Escaping.
|
// Escaping.
|
||||||
'\\' => true,
|
'\\' => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -198,21 +221,6 @@ impl<'s> Tokens<'s> {
|
|||||||
Token::Text(self.s.eaten_from(start))
|
Token::Text(self.s.eaten_from(start))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash(&mut self, start: usize) -> Token<'s> {
|
|
||||||
if self.s.check(is_id_start) {
|
|
||||||
self.s.eat();
|
|
||||||
self.s.eat_while(is_id_continue);
|
|
||||||
let read = self.s.eaten_from(start);
|
|
||||||
if let Some(keyword) = keyword(read) {
|
|
||||||
keyword
|
|
||||||
} else {
|
|
||||||
Token::Invalid(read)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Token::Hash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn raw(&mut self) -> Token<'s> {
|
fn raw(&mut self) -> Token<'s> {
|
||||||
let mut backticks = 1;
|
let mut backticks = 1;
|
||||||
while self.s.eat_if('`') {
|
while self.s.eat_if('`') {
|
||||||
@ -276,10 +284,10 @@ impl<'s> Tokens<'s> {
|
|||||||
match c {
|
match c {
|
||||||
// Backslash and comments.
|
// Backslash and comments.
|
||||||
'\\' | '/' |
|
'\\' | '/' |
|
||||||
// Parenthesis.
|
// Parenthesis and hashtag.
|
||||||
'[' | ']' | '{' | '}' |
|
'[' | ']' | '{' | '}' | '#' |
|
||||||
// Markup.
|
// Markup.
|
||||||
'*' | '_' | '#' | '~' | '`' | '$' => {
|
'*' | '_' | '=' | '~' | '`' | '$' => {
|
||||||
let start = self.s.index();
|
let start = self.s.index();
|
||||||
self.s.eat_assert(c);
|
self.s.eat_assert(c);
|
||||||
Token::Text(&self.s.eaten_from(start))
|
Token::Text(&self.s.eaten_from(start))
|
||||||
@ -367,18 +375,6 @@ impl<'s> Tokens<'s> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hex(&mut self, start: usize) -> Token<'s> {
|
|
||||||
self.s.eat_while(is_id_continue);
|
|
||||||
let read = self.s.eaten_from(start);
|
|
||||||
if let Some(keyword) = keyword(read) {
|
|
||||||
keyword
|
|
||||||
} else if let Ok(color) = RgbaColor::from_str(read) {
|
|
||||||
Token::Color(color)
|
|
||||||
} else {
|
|
||||||
Token::Invalid(read)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn string(&mut self) -> Token<'s> {
|
fn string(&mut self) -> Token<'s> {
|
||||||
let mut escaped = false;
|
let mut escaped = false;
|
||||||
Token::Str(TokenStr {
|
Token::Str(TokenStr {
|
||||||
@ -596,8 +592,8 @@ mod tests {
|
|||||||
// Test markup tokens.
|
// Test markup tokens.
|
||||||
t!(Markup[" a1"]: "*" => Star);
|
t!(Markup[" a1"]: "*" => Star);
|
||||||
t!(Markup: "_" => Underscore);
|
t!(Markup: "_" => Underscore);
|
||||||
t!(Markup[""]: "###" => Hash, Hash, Hash);
|
t!(Markup[""]: "===" => Eq, Eq, Eq);
|
||||||
t!(Markup["a1/"]: "# " => Hash, Space(0));
|
t!(Markup["a1/"]: "= " => Eq, Space(0));
|
||||||
t!(Markup: "~" => Tilde);
|
t!(Markup: "~" => Tilde);
|
||||||
t!(Markup[" "]: r"\" => Backslash);
|
t!(Markup[" "]: r"\" => Backslash);
|
||||||
}
|
}
|
||||||
@ -655,10 +651,9 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for &(s, t) in &both {
|
for &(s, t) in &both {
|
||||||
t!(Code[" "]: format!("#{}", s) => t);
|
t!(Both[" "]: format!("#{}", s) => t);
|
||||||
t!(Markup[" "]: format!("#{}", s) => t);
|
t!(Both[" "]: format!("#{0}#{0}", s) => t, t);
|
||||||
t!(Markup[" "]: format!("#{0}#{0}", s) => t, t);
|
t!(Markup[" /"]: format!("# {}", s) => Token::Invalid("#"), Space(0), Text(s));
|
||||||
t!(Markup[" /"]: format!("# {}", s) => Hash, Space(0), Text(s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let code = [
|
let code = [
|
||||||
@ -713,7 +708,7 @@ mod tests {
|
|||||||
|
|
||||||
// Test code symbols in text.
|
// Test code symbols in text.
|
||||||
t!(Markup[" /"]: "a():\"b" => Text("a():\"b"));
|
t!(Markup[" /"]: "a():\"b" => Text("a():\"b"));
|
||||||
t!(Markup[" /"]: ";:,=|/+-" => Text(";:,=|/+-"));
|
t!(Markup[" /"]: ";:,|/+-" => Text(";:,|/+-"));
|
||||||
|
|
||||||
// Test text ends.
|
// Test text ends.
|
||||||
t!(Markup[""]: "hello " => Text("hello"), Space(0));
|
t!(Markup[""]: "hello " => Text("hello"), Space(0));
|
||||||
@ -765,17 +760,17 @@ mod tests {
|
|||||||
t!(Markup: r"\}" => Text("}"));
|
t!(Markup: r"\}" => Text("}"));
|
||||||
t!(Markup: r"\*" => Text("*"));
|
t!(Markup: r"\*" => Text("*"));
|
||||||
t!(Markup: r"\_" => Text("_"));
|
t!(Markup: r"\_" => Text("_"));
|
||||||
t!(Markup: r"\#" => Text("#"));
|
t!(Markup: r"\=" => Text("="));
|
||||||
t!(Markup: r"\~" => Text("~"));
|
t!(Markup: r"\~" => Text("~"));
|
||||||
t!(Markup: r"\`" => Text("`"));
|
t!(Markup: r"\`" => Text("`"));
|
||||||
t!(Markup: r"\$" => Text("$"));
|
t!(Markup: r"\$" => Text("$"));
|
||||||
|
t!(Markup: r"\#" => Text("#"));
|
||||||
|
|
||||||
// Test unescapable symbols.
|
// Test unescapable symbols.
|
||||||
t!(Markup[" /"]: r"\a" => Text(r"\"), Text("a"));
|
t!(Markup[" /"]: r"\a" => Text(r"\"), Text("a"));
|
||||||
t!(Markup[" /"]: r"\u" => Text(r"\"), Text("u"));
|
t!(Markup[" /"]: r"\u" => Text(r"\"), Text("u"));
|
||||||
t!(Markup[" /"]: r"\1" => Text(r"\"), Text("1"));
|
t!(Markup[" /"]: r"\1" => Text(r"\"), Text("1"));
|
||||||
t!(Markup[" /"]: r"\:" => Text(r"\"), Text(":"));
|
t!(Markup[" /"]: r"\:" => Text(r"\"), Text(":"));
|
||||||
t!(Markup[" /"]: r"\=" => Text(r"\"), Text("="));
|
|
||||||
t!(Markup[" /"]: r#"\""# => Text(r"\"), Text("\""));
|
t!(Markup[" /"]: r#"\""# => Text(r"\"), Text("\""));
|
||||||
|
|
||||||
// Test basic unicode escapes.
|
// Test basic unicode escapes.
|
||||||
@ -947,7 +942,7 @@ mod tests {
|
|||||||
t!(Code: "1%%" => Percent(1.0), Invalid("%"));
|
t!(Code: "1%%" => Percent(1.0), Invalid("%"));
|
||||||
|
|
||||||
// Test invalid keyword.
|
// Test invalid keyword.
|
||||||
t!(Markup[" /"]: "#-" => Hash, Text("-"));
|
t!(Markup[" /"]: "#-" => Invalid("#-"));
|
||||||
t!(Markup[" /"]: "#do" => Invalid("#do"));
|
t!(Markup[" /"]: "#do" => Invalid("#do"));
|
||||||
t!(Code[" /"]: r"#letter" => Invalid(r"#letter"));
|
t!(Code[" /"]: r"#letter" => Invalid(r"#letter"));
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ pub enum Expr {
|
|||||||
Unary(ExprUnary),
|
Unary(ExprUnary),
|
||||||
/// A binary operation: `a + b`.
|
/// A binary operation: `a + b`.
|
||||||
Binary(ExprBinary),
|
Binary(ExprBinary),
|
||||||
/// An invocation of a function: `foo(...)`, `[foo ...]`.
|
/// An invocation of a function: `foo(...)`, `#[foo ...]`.
|
||||||
Call(ExprCall),
|
Call(ExprCall),
|
||||||
/// A let expression: `#let x = 1`.
|
/// A let expression: `#let x = 1`.
|
||||||
Let(ExprLet),
|
Let(ExprLet),
|
||||||
@ -75,11 +75,7 @@ impl Pretty for Expr {
|
|||||||
Self::Str(v) => write!(p, "{:?}", &v).unwrap(),
|
Self::Str(v) => write!(p, "{:?}", &v).unwrap(),
|
||||||
Self::Array(v) => v.pretty(p),
|
Self::Array(v) => v.pretty(p),
|
||||||
Self::Dict(v) => v.pretty(p),
|
Self::Dict(v) => v.pretty(p),
|
||||||
Self::Template(v) => {
|
Self::Template(v) => pretty_template(v, p),
|
||||||
p.push_str("[");
|
|
||||||
v.pretty(p);
|
|
||||||
p.push_str("]");
|
|
||||||
}
|
|
||||||
Self::Group(v) => {
|
Self::Group(v) => {
|
||||||
p.push_str("(");
|
p.push_str("(");
|
||||||
v.v.pretty(p);
|
v.v.pretty(p);
|
||||||
@ -146,6 +142,17 @@ impl Pretty for Named {
|
|||||||
/// A template expression: `[*Hi* there!]`.
|
/// A template expression: `[*Hi* there!]`.
|
||||||
pub type ExprTemplate = Tree;
|
pub type ExprTemplate = Tree;
|
||||||
|
|
||||||
|
/// Pretty print a template.
|
||||||
|
pub fn pretty_template(template: &ExprTemplate, p: &mut Printer) {
|
||||||
|
if let [Spanned { v: Node::Expr(Expr::Call(call)), .. }] = template.as_slice() {
|
||||||
|
pretty_func_template(call, p, false)
|
||||||
|
} else {
|
||||||
|
p.push_str("[");
|
||||||
|
template.pretty(p);
|
||||||
|
p.push_str("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A grouped expression: `(1 + 2)`.
|
/// A grouped expression: `(1 + 2)`.
|
||||||
pub type ExprGroup = SpanBox<Expr>;
|
pub type ExprGroup = SpanBox<Expr>;
|
||||||
|
|
||||||
@ -400,7 +407,7 @@ pub enum Associativity {
|
|||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An invocation of a function: `foo(...)`, `[foo ...]`.
|
/// An invocation of a function: `foo(...)`, `#[foo ...]`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprCall {
|
pub struct ExprCall {
|
||||||
/// The callee of the function.
|
/// The callee of the function.
|
||||||
@ -418,12 +425,12 @@ impl Pretty for ExprCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pretty print a bracketed function call, with body or chaining when possible.
|
/// Pretty print a function template, with body or chaining when possible.
|
||||||
pub fn pretty_bracket_call(call: &ExprCall, p: &mut Printer, chained: bool) {
|
pub fn pretty_func_template(call: &ExprCall, p: &mut Printer, chained: bool) {
|
||||||
if chained {
|
if chained {
|
||||||
p.push_str(" | ");
|
p.push_str(" | ");
|
||||||
} else {
|
} else {
|
||||||
p.push_str("[");
|
p.push_str("#[");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function name.
|
// Function name.
|
||||||
@ -431,7 +438,7 @@ pub fn pretty_bracket_call(call: &ExprCall, p: &mut Printer, chained: bool) {
|
|||||||
|
|
||||||
// Find out whether this can be written with a body or as a chain.
|
// Find out whether this can be written with a body or as a chain.
|
||||||
//
|
//
|
||||||
// Example: Transforms "[v [Hi]]" => "[v][Hi]".
|
// Example: Transforms "#[v [Hi]]" => "#[v][Hi]".
|
||||||
if let [head @ .., Argument::Pos(Spanned { v: Expr::Template(template), .. })] =
|
if let [head @ .., Argument::Pos(Spanned { v: Expr::Template(template), .. })] =
|
||||||
call.args.v.as_slice()
|
call.args.v.as_slice()
|
||||||
{
|
{
|
||||||
@ -443,9 +450,9 @@ pub fn pretty_bracket_call(call: &ExprCall, p: &mut Printer, chained: bool) {
|
|||||||
|
|
||||||
// Find out whether this can written as a chain.
|
// Find out whether this can written as a chain.
|
||||||
//
|
//
|
||||||
// Example: Transforms "[v][[f]]" => "[v | f]".
|
// Example: Transforms "#[v][[f]]" => "#[v | f]".
|
||||||
if let [Spanned { v: Node::Expr(Expr::Call(call)), .. }] = template.as_slice() {
|
if let [Spanned { v: Node::Expr(Expr::Call(call)), .. }] = template.as_slice() {
|
||||||
return pretty_bracket_call(call, p, true);
|
return pretty_func_template(call, p, true);
|
||||||
} else {
|
} else {
|
||||||
p.push_str("][");
|
p.push_str("][");
|
||||||
template.pretty(p);
|
template.pretty(p);
|
||||||
|
@ -60,7 +60,7 @@ mod tests {
|
|||||||
roundtrip("hi");
|
roundtrip("hi");
|
||||||
|
|
||||||
// Heading.
|
// Heading.
|
||||||
roundtrip("# *Ok*");
|
roundtrip("= *Ok*");
|
||||||
|
|
||||||
// Raw.
|
// Raw.
|
||||||
roundtrip("`lang 1`");
|
roundtrip("`lang 1`");
|
||||||
@ -94,9 +94,9 @@ mod tests {
|
|||||||
roundtrip("{(a: 1, b: 2)}");
|
roundtrip("{(a: 1, b: 2)}");
|
||||||
|
|
||||||
// Templates.
|
// Templates.
|
||||||
roundtrip("{[]}");
|
roundtrip("[]");
|
||||||
roundtrip("{[*Ok*]}");
|
roundtrip("[*Ok*]");
|
||||||
roundtrip("{[[f]]}");
|
roundtrip("{[f]}");
|
||||||
|
|
||||||
// Groups.
|
// Groups.
|
||||||
roundtrip("{(1)}");
|
roundtrip("{(1)}");
|
||||||
@ -105,6 +105,7 @@ mod tests {
|
|||||||
roundtrip("{}");
|
roundtrip("{}");
|
||||||
roundtrip("{1}");
|
roundtrip("{1}");
|
||||||
roundtrip("{ #let x = 1; x += 2; x + 1 }");
|
roundtrip("{ #let x = 1; x += 2; x + 1 }");
|
||||||
|
roundtrip("[{}]");
|
||||||
|
|
||||||
// Operators.
|
// Operators.
|
||||||
roundtrip("{-x}");
|
roundtrip("{-x}");
|
||||||
@ -116,14 +117,14 @@ mod tests {
|
|||||||
roundtrip("{v(1)}");
|
roundtrip("{v(1)}");
|
||||||
roundtrip("{v(a: 1, b)}");
|
roundtrip("{v(a: 1, b)}");
|
||||||
|
|
||||||
// Bracket calls.
|
// Function templates.
|
||||||
roundtrip("[v]");
|
roundtrip("#[v]");
|
||||||
roundtrip("[v 1]");
|
roundtrip("#[v 1]");
|
||||||
roundtrip("[v 1, 2][*Ok*]");
|
roundtrip("#[v 1, 2][*Ok*]");
|
||||||
roundtrip("[v 1 | f 2]");
|
roundtrip("#[v 1 | f 2]");
|
||||||
roundtrip("{[[v]]}");
|
roundtrip("{#[v]}");
|
||||||
test("[v 1, [[f 2]]]", "[v 1 | f 2]");
|
test("#[v 1, #[f 2]]", "#[v 1 | f 2]");
|
||||||
test("[v 1, 2][[f 3]]", "[v 1, 2 | f 3]");
|
test("#[v 1, 2][#[f 3]]", "#[v 1, 2 | f 3]");
|
||||||
|
|
||||||
// Keywords.
|
// Keywords.
|
||||||
roundtrip("#let x = 1 + 2");
|
roundtrip("#let x = 1 + 2");
|
||||||
|
@ -36,8 +36,8 @@ impl Pretty for Node {
|
|||||||
Self::Raw(raw) => raw.pretty(p),
|
Self::Raw(raw) => raw.pretty(p),
|
||||||
Self::Expr(expr) => {
|
Self::Expr(expr) => {
|
||||||
if let Expr::Call(call) = expr {
|
if let Expr::Call(call) = expr {
|
||||||
// Format bracket calls appropriately.
|
// Format function templates appropriately.
|
||||||
pretty_bracket_call(call, p, false)
|
pretty_func_template(call, p, false)
|
||||||
} else {
|
} else {
|
||||||
expr.pretty(p);
|
expr.pretty(p);
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ pub struct NodeHeading {
|
|||||||
impl Pretty for NodeHeading {
|
impl Pretty for NodeHeading {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
for _ in 0 ..= self.level.v {
|
for _ in 0 ..= self.level.v {
|
||||||
p.push_str("#");
|
p.push_str("=");
|
||||||
}
|
}
|
||||||
self.contents.pretty(p);
|
self.contents.pretty(p);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ use crate::geom::{AngularUnit, LengthUnit};
|
|||||||
pub enum Token<'s> {
|
pub enum Token<'s> {
|
||||||
/// A left square bracket: `[`.
|
/// A left square bracket: `[`.
|
||||||
LeftBracket,
|
LeftBracket,
|
||||||
|
/// A hashtag followed by a left square bracket: `#[`.
|
||||||
|
HashBracket,
|
||||||
/// A right square bracket: `]`.
|
/// A right square bracket: `]`.
|
||||||
RightBracket,
|
RightBracket,
|
||||||
/// A left curly brace: `{`.
|
/// A left curly brace: `{`.
|
||||||
@ -20,8 +22,8 @@ pub enum Token<'s> {
|
|||||||
Star,
|
Star,
|
||||||
/// An underscore: `_`.
|
/// An underscore: `_`.
|
||||||
Underscore,
|
Underscore,
|
||||||
/// A hashtag: `#`.
|
/// A single equals sign: `=`.
|
||||||
Hash,
|
Eq,
|
||||||
/// A tilde: `~`.
|
/// A tilde: `~`.
|
||||||
Tilde,
|
Tilde,
|
||||||
/// A backslash followed by nothing or whitespace: `\`.
|
/// A backslash followed by nothing or whitespace: `\`.
|
||||||
@ -40,8 +42,6 @@ pub enum Token<'s> {
|
|||||||
Hyph,
|
Hyph,
|
||||||
/// A slash: `/`.
|
/// A slash: `/`.
|
||||||
Slash,
|
Slash,
|
||||||
/// A single equals sign: `=`.
|
|
||||||
Eq,
|
|
||||||
/// Two equals signs: `==`.
|
/// Two equals signs: `==`.
|
||||||
EqEq,
|
EqEq,
|
||||||
/// An exclamation mark followed by an equals sign: `!=`.
|
/// An exclamation mark followed by an equals sign: `!=`.
|
||||||
@ -191,6 +191,7 @@ impl<'s> Token<'s> {
|
|||||||
pub fn name(self) -> &'static str {
|
pub fn name(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::LeftBracket => "opening bracket",
|
Self::LeftBracket => "opening bracket",
|
||||||
|
Self::HashBracket => "start of function template",
|
||||||
Self::RightBracket => "closing bracket",
|
Self::RightBracket => "closing bracket",
|
||||||
Self::LeftBrace => "opening brace",
|
Self::LeftBrace => "opening brace",
|
||||||
Self::RightBrace => "closing brace",
|
Self::RightBrace => "closing brace",
|
||||||
@ -198,7 +199,6 @@ impl<'s> Token<'s> {
|
|||||||
Self::RightParen => "closing paren",
|
Self::RightParen => "closing paren",
|
||||||
Self::Star => "star",
|
Self::Star => "star",
|
||||||
Self::Underscore => "underscore",
|
Self::Underscore => "underscore",
|
||||||
Self::Hash => "hashtag",
|
|
||||||
Self::Tilde => "tilde",
|
Self::Tilde => "tilde",
|
||||||
Self::Backslash => "backslash",
|
Self::Backslash => "backslash",
|
||||||
Self::Comma => "comma",
|
Self::Comma => "comma",
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
[page width: 450pt, height: 300pt, margins: 1cm]
|
#[page width: 450pt, height: 300pt, margins: 1cm]
|
||||||
|
|
||||||
[box][
|
#[box][
|
||||||
*Technische Universität Berlin* \
|
*Technische Universität Berlin* \
|
||||||
*Fakultät II, Institut for Mathematik* \
|
*Fakultät II, Institut for Mathematik* \
|
||||||
Sekretariat MA \
|
Sekretariat MA \
|
||||||
Dr. Max Mustermann \
|
Dr. Max Mustermann \
|
||||||
Ola Nordmann, John Doe
|
Ola Nordmann, John Doe
|
||||||
]
|
]
|
||||||
[align right | box][*WiSe 2019/2020* \ Woche 3]
|
#[align right | box][*WiSe 2019/2020* \ Woche 3]
|
||||||
|
|
||||||
[v 6mm]
|
#[v 6mm]
|
||||||
|
|
||||||
[align center][
|
#[align center][
|
||||||
#### 3. Übungsblatt Computerorientierte Mathematik II [v 2mm]
|
==== 3. Übungsblatt Computerorientierte Mathematik II #[v 2mm]
|
||||||
*Abgabe: 03.05.2019* (bis 10:10 Uhr in MA 001) [v 2mm]
|
*Abgabe: 03.05.2019* (bis 10:10 Uhr in MA 001) #[v 2mm]
|
||||||
*Alle Antworten sind zu beweisen.*
|
*Alle Antworten sind zu beweisen.*
|
||||||
]
|
]
|
||||||
|
|
||||||
*1. Aufgabe* [align right][(1 + 1 + 2 Punkte)]
|
*1. Aufgabe* #[align right][(1 + 1 + 2 Punkte)]
|
||||||
|
|
||||||
Ein _Binärbaum_ ist ein Wurzelbaum, in dem jeder Knoten ≤ 2 Kinder hat.
|
Ein _Binärbaum_ ist ein Wurzelbaum, in dem jeder Knoten ≤ 2 Kinder hat.
|
||||||
Die Tiefe eines Knotens _v_ ist die Länge des eindeutigen Weges von der Wurzel
|
Die Tiefe eines Knotens _v_ ist die Länge des eindeutigen Weges von der Wurzel
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.2 KiB |
@ -1,25 +1,25 @@
|
|||||||
// Basic call, whitespace insignificant.
|
// Basic call, whitespace insignificant.
|
||||||
[f], [ f ], [
|
#[f], #[ f ], #[
|
||||||
f
|
f
|
||||||
]
|
]
|
||||||
|
|
||||||
[f bold]
|
#[f bold]
|
||||||
|
|
||||||
[f 1,]
|
#[f 1,]
|
||||||
|
|
||||||
[f a:2]
|
#[f a:2]
|
||||||
|
|
||||||
[f 1, a: (3, 4), 2, b: "5"]
|
#[f 1, a: (3, 4), 2, b: "5"]
|
||||||
|
|
||||||
---
|
---
|
||||||
// Body and no body.
|
// Body and no body.
|
||||||
[f][[f]]
|
#[f][#[f]]
|
||||||
|
|
||||||
// Lots of potential bodies.
|
// Lots of potential bodies.
|
||||||
[f][f][f]
|
#[f][f]#[f]
|
||||||
|
|
||||||
// Multi-paragraph body.
|
// Multi-paragraph body.
|
||||||
[box][
|
#[box][
|
||||||
First
|
First
|
||||||
|
|
||||||
Second
|
Second
|
||||||
@ -27,81 +27,81 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
// Chained.
|
// Chained.
|
||||||
[f | f]
|
#[f | f]
|
||||||
|
|
||||||
// Multi-chain.
|
// Multi-chain.
|
||||||
[f|f|f]
|
#[f|f|f]
|
||||||
|
|
||||||
// With body.
|
// With body.
|
||||||
// Error: 1:6-1:7 expected identifier, found integer
|
// Error: 1:7-1:8 expected identifier, found integer
|
||||||
[f | 1 | box][💕]
|
#[f | 1 | box][💕]
|
||||||
|
|
||||||
// Error: 2:2-2:2 expected identifier
|
// Error: 2:3-2:3 expected identifier
|
||||||
// Error: 1:3-1:3 expected identifier
|
// Error: 1:4-1:4 expected identifier
|
||||||
[||f true]
|
#[||f true]
|
||||||
|
|
||||||
// Error: 1:6-1:6 expected identifier
|
// Error: 1:7-1:7 expected identifier
|
||||||
[f 1|]
|
#[f 1|]
|
||||||
|
|
||||||
// Error: 2:2-2:2 expected identifier
|
// Error: 2:3-2:3 expected identifier
|
||||||
// Error: 1:3-1:3 expected identifier
|
// Error: 1:4-1:4 expected identifier
|
||||||
[|][Nope]
|
#[|][Nope]
|
||||||
|
|
||||||
// Error: 2:5-2:5 expected closing paren
|
// Error: 2:6-2:6 expected closing paren
|
||||||
// Error: 1:8-1:9 expected expression, found closing paren
|
// Error: 1:9-1:10 expected expression, found closing paren
|
||||||
[f (|f )]
|
#[f (|f )]
|
||||||
|
|
||||||
// With actual functions.
|
// With actual functions.
|
||||||
[box width: 1cm | image "res/rhino.png"]
|
#[box width: 1cm | image "res/rhino.png"]
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 1:4-1:6 expected expression, found end of block comment
|
// Error: 1:5-1:7 expected expression, found end of block comment
|
||||||
[f */]
|
#[f */]
|
||||||
|
|
||||||
// Error: 1:7-1:8 expected expression, found colon
|
// Error: 1:8-1:9 expected expression, found colon
|
||||||
[f a:1:]
|
#[f a:1:]
|
||||||
|
|
||||||
// Error: 1:5-1:5 expected comma
|
// Error: 1:6-1:6 expected comma
|
||||||
[f 1 2]
|
#[f 1 2]
|
||||||
|
|
||||||
// Error: 2:4-2:5 expected identifier
|
// Error: 2:5-2:6 expected identifier
|
||||||
// Error: 1:6-1:6 expected expression
|
// Error: 1:7-1:7 expected expression
|
||||||
[f 1:]
|
#[f 1:]
|
||||||
|
|
||||||
// Error: 1:4-1:5 expected identifier
|
// Error: 1:5-1:6 expected identifier
|
||||||
[f 1:2]
|
#[f 1:2]
|
||||||
|
|
||||||
// Error: 1:4-1:7 expected identifier
|
// Error: 1:5-1:8 expected identifier
|
||||||
[f (x):1]
|
#[f (x):1]
|
||||||
|
|
||||||
---
|
---
|
||||||
// Ref: false
|
// Ref: false
|
||||||
// Error: 2:2-2:3 expected function, found string
|
// Error: 2:3-2:4 expected function, found string
|
||||||
#let x = "string"
|
#let x = "string"
|
||||||
[x]
|
#[x]
|
||||||
|
|
||||||
// Error: 1:2-1:3 expected identifier, found invalid token
|
// Error: 1:3-1:4 expected identifier, found invalid token
|
||||||
[# 1]
|
#[# 1]
|
||||||
|
|
||||||
// Error: 4:1-4:1 expected identifier
|
// Error: 4:1-4:1 expected identifier
|
||||||
// Error: 3:1-3:1 expected closing bracket
|
// Error: 3:1-3:1 expected closing bracket
|
||||||
[
|
#[
|
||||||
|
|
||||||
---
|
---
|
||||||
// Ref: false
|
// Ref: false
|
||||||
// Error: 2:2-2:3 expected identifier, found closing paren
|
// Error: 2:3-2:4 expected identifier, found closing paren
|
||||||
// Error: 3:1-3:1 expected closing bracket
|
// Error: 3:1-3:1 expected closing bracket
|
||||||
[)
|
#[)
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 3:1-3:1 expected closing bracket
|
// Error: 3:1-3:1 expected closing bracket
|
||||||
[f [*]
|
#[f [*]
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 3:1-3:1 expected closing bracket
|
// Error: 3:1-3:1 expected closing bracket
|
||||||
[f][`a]`
|
#[f][`a]`
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 3:1-3:1 expected quote
|
// Error: 3:1-3:1 expected quote
|
||||||
// Error: 2:1-2:1 expected closing bracket
|
// Error: 2:1-2:1 expected closing bracket
|
||||||
[f "]
|
#[f "]
|
||||||
|
@ -8,7 +8,7 @@ C/*
|
|||||||
*/D
|
*/D
|
||||||
|
|
||||||
// Works in headers.
|
// Works in headers.
|
||||||
[f /*1*/ a: "b" //
|
#[f /*1*/ a: "b" //
|
||||||
, 1]
|
, 1]
|
||||||
|
|
||||||
// End should not appear without start.
|
// End should not appear without start.
|
||||||
|
@ -5,7 +5,7 @@ _Emph_ and *strong*!
|
|||||||
Pa_rtl_y emphasized or str*ength*ened.
|
Pa_rtl_y emphasized or str*ength*ened.
|
||||||
|
|
||||||
// Scoped to body.
|
// Scoped to body.
|
||||||
[box][*Sco_ped] to body.
|
#[box][*Sco_ped] to body.
|
||||||
|
|
||||||
// Unterminated is fine.
|
// Unterminated is fine.
|
||||||
_The End
|
_The End
|
||||||
|
@ -7,75 +7,75 @@
|
|||||||
#let error = +""
|
#let error = +""
|
||||||
|
|
||||||
// Paren call.
|
// Paren call.
|
||||||
[test f(1), "f(1)"]
|
#[test f(1), "f(1)"]
|
||||||
[test type(1), "integer"]
|
#[test type(1), "integer"]
|
||||||
|
|
||||||
// Unary operations.
|
// Unary operations.
|
||||||
[test +1, 1]
|
#[test +1, 1]
|
||||||
[test -1, 1-2]
|
#[test -1, 1-2]
|
||||||
[test --1, 1]
|
#[test --1, 1]
|
||||||
|
|
||||||
// Math operations.
|
// Math operations.
|
||||||
[test "a" + "b", "ab"]
|
#[test "a" + "b", "ab"]
|
||||||
[test 1-4, 3*-1]
|
#[test 1-4, 3*-1]
|
||||||
[test a * b, 8]
|
#[test a * b, 8]
|
||||||
[test 12pt/.4, 30pt]
|
#[test 12pt/.4, 30pt]
|
||||||
[test 1e+2-1e-2, 99.99]
|
#[test 1e+2-1e-2, 99.99]
|
||||||
|
|
||||||
// Associativity.
|
// Associativity.
|
||||||
[test 1+2+3, 6]
|
#[test 1+2+3, 6]
|
||||||
[test 1/2*3, 1.5]
|
#[test 1/2*3, 1.5]
|
||||||
|
|
||||||
// Precedence.
|
// Precedence.
|
||||||
[test 1+2*-3, -5]
|
#[test 1+2*-3, -5]
|
||||||
|
|
||||||
// Short-circuiting logical operators.
|
// Short-circuiting logical operators.
|
||||||
[test not "a" == "b", true]
|
#[test not "a" == "b", true]
|
||||||
[test not 7 < 4 and 10 == 10, true]
|
#[test not 7 < 4 and 10 == 10, true]
|
||||||
[test 3 < 2 or 4 < 5, true]
|
#[test 3 < 2 or 4 < 5, true]
|
||||||
[test false and false or true, true]
|
#[test false and false or true, true]
|
||||||
|
|
||||||
// Right-hand side not even evaluated.
|
// Right-hand side not even evaluated.
|
||||||
[test false and dont-care, false]
|
#[test false and dont-care, false]
|
||||||
[test true or dont-care, true]
|
#[test true or dont-care, true]
|
||||||
|
|
||||||
// Equality and inequality.
|
// Equality and inequality.
|
||||||
[test "ab" == "a" + "b", true]
|
#[test "ab" == "a" + "b", true]
|
||||||
[test [*Hi*] == [*Hi*], true]
|
#[test [*Hi*] == [*Hi*], true]
|
||||||
[test "a" != "a", false]
|
#[test "a" != "a", false]
|
||||||
[test [*] != [_], true]
|
#[test [*] != [_], true]
|
||||||
[test (1, 2, 3) == (1, 2) + (3,), true]
|
#[test (1, 2, 3) == (1, 2) + (3,), true]
|
||||||
[test () == (1,), false]
|
#[test () == (1,), false]
|
||||||
[test (a: 1, b: 2) == (b: 2, a: 1), true]
|
#[test (a: 1, b: 2) == (b: 2, a: 1), true]
|
||||||
[test (:) == (a: 1), false]
|
#[test (:) == (a: 1), false]
|
||||||
[test 1 == "hi", false]
|
#[test 1 == "hi", false]
|
||||||
[test 1 == 1.0, true]
|
#[test 1 == 1.0, true]
|
||||||
[test 30% == 30% + 0cm, true]
|
#[test 30% == 30% + 0cm, true]
|
||||||
[test 1in == 0% + 72pt, true]
|
#[test 1in == 0% + 72pt, true]
|
||||||
[test 30% == 30% + 1cm, false]
|
#[test 30% == 30% + 1cm, false]
|
||||||
|
|
||||||
// Comparisons.
|
// Comparisons.
|
||||||
[test 13 * 3 < 14 * 4, true]
|
#[test 13 * 3 < 14 * 4, true]
|
||||||
[test 5 < 10, true]
|
#[test 5 < 10, true]
|
||||||
[test 5 > 5, false]
|
#[test 5 > 5, false]
|
||||||
[test 5 <= 5, true]
|
#[test 5 <= 5, true]
|
||||||
[test 5 <= 4, false]
|
#[test 5 <= 4, false]
|
||||||
[test 45deg < 1rad, true]
|
#[test 45deg < 1rad, true]
|
||||||
|
|
||||||
// Assignment.
|
// Assignment.
|
||||||
#let x = "some"
|
#let x = "some"
|
||||||
#let y = "some"
|
#let y = "some"
|
||||||
[test (x = y = "") == none and x == none and y == "", true]
|
#[test (x = y = "") == none and x == none and y == "", true]
|
||||||
|
|
||||||
// Modify-assign operators.
|
// Modify-assign operators.
|
||||||
#let x = 0
|
#let x = 0
|
||||||
{ x = 10 } [test x, 10]
|
{ x = 10 } #[test x, 10]
|
||||||
{ x -= 5 } [test x, 5]
|
{ x -= 5 } #[test x, 5]
|
||||||
{ x += 1 } [test x, 6]
|
{ x += 1 } #[test x, 6]
|
||||||
{ x *= x } [test x, 36]
|
{ x *= x } #[test x, 36]
|
||||||
{ x /= 2.0 } [test x, 18.0]
|
{ x /= 2.0 } #[test x, 18.0]
|
||||||
{ x = "some" } [test x, "some"]
|
{ x = "some" } #[test x, "some"]
|
||||||
{ x += "thing" } [test x, "something"]
|
{ x += "thing" } #[test x, "something"]
|
||||||
|
|
||||||
// Error: 1:3-1:4 unknown variable
|
// Error: 1:3-1:4 unknown variable
|
||||||
{ z = 1 }
|
{ z = 1 }
|
||||||
@ -94,21 +94,21 @@
|
|||||||
#let box = ""; { box = "hi" }
|
#let box = ""; { box = "hi" }
|
||||||
|
|
||||||
// Parentheses.
|
// Parentheses.
|
||||||
[test (a), 2]
|
#[test (a), 2]
|
||||||
[test (2), 2]
|
#[test (2), 2]
|
||||||
[test (1+2)*3, 9]
|
#[test (1+2)*3, 9]
|
||||||
|
|
||||||
// Error: 1:3-1:3 expected expression
|
// Error: 1:3-1:3 expected expression
|
||||||
{-}
|
{-}
|
||||||
|
|
||||||
// Error: 1:10-1:10 expected expression
|
// Error: 1:11-1:11 expected expression
|
||||||
[test {1+}, 1]
|
#[test {1+}, 1]
|
||||||
|
|
||||||
// Error: 1:10-1:10 expected expression
|
// Error: 1:11-1:11 expected expression
|
||||||
[test {2*}, 2]
|
#[test {2*}, 2]
|
||||||
|
|
||||||
// Error: 1:7-1:16 cannot apply '-' to boolean
|
// Error: 1:8-1:17 cannot apply '-' to boolean
|
||||||
[test -not true, error]
|
#[test -not true, error]
|
||||||
|
|
||||||
// Error: 1:2-1:8 cannot apply 'not' to array
|
// Error: 1:2-1:8 cannot apply 'not' to array
|
||||||
{not ()}
|
{not ()}
|
||||||
|
@ -1,48 +1,41 @@
|
|||||||
// Test different numbers of hashtags.
|
// Test different numbers of hashtags.
|
||||||
|
|
||||||
// Valid levels.
|
// Valid levels.
|
||||||
# One
|
= One
|
||||||
### Three
|
=== Three
|
||||||
###### Six
|
====== Six
|
||||||
|
|
||||||
// Too many hashtags.
|
// Too many hashtags.
|
||||||
// Warning: 1:1-1:8 should not exceed depth 6
|
// Warning: 1:1-1:8 should not exceed depth 6
|
||||||
####### Seven
|
======= Seven
|
||||||
|
|
||||||
---
|
---
|
||||||
// Test heading vs. no heading.
|
// Test heading vs. no heading.
|
||||||
|
|
||||||
// Parsed as headings if at start of the context.
|
// Parsed as headings if at start of the context.
|
||||||
/**/ # Heading
|
/**/ = Heading
|
||||||
{[## Heading]}
|
{[== Heading]}
|
||||||
[box][### Heading]
|
#[box][=== Heading]
|
||||||
|
|
||||||
// Not at the start of the context.
|
// Not at the start of the context.
|
||||||
Text with # hashtag
|
Text = with=sign
|
||||||
|
|
||||||
// Escaped.
|
// Escaped.
|
||||||
\# No heading
|
\= No heading
|
||||||
|
|
||||||
// Keyword.
|
|
||||||
// Error: 1:1-1:6 unexpected invalid token
|
|
||||||
#nope
|
|
||||||
|
|
||||||
// Not parsed as a keyword, but neither as a heading.
|
|
||||||
Nr#1
|
|
||||||
|
|
||||||
---
|
---
|
||||||
// Heading continuation over linebreak.
|
// Heading continuation over linebreak.
|
||||||
|
|
||||||
// Code blocks continue heading.
|
// Code blocks continue heading.
|
||||||
# This {
|
= This {
|
||||||
"continues"
|
"continues"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function call continues heading.
|
// Function call continues heading.
|
||||||
# [box][
|
= #[box][
|
||||||
This,
|
This,
|
||||||
] too
|
] too
|
||||||
|
|
||||||
// Without some kind of block, headings end at a line break.
|
// Without some kind of block, headings end at a line break.
|
||||||
# This
|
= This
|
||||||
not
|
not
|
||||||
|
@ -52,8 +52,7 @@ a#if x b#if (x)c
|
|||||||
a#if true [b] #else c
|
a#if true [b] #else c
|
||||||
|
|
||||||
// Lone else.
|
// Lone else.
|
||||||
// Error: 2:1-2:6 unexpected keyword `#else`
|
// Error: 1:1-1:6 unexpected keyword `#else`
|
||||||
// Error: 1:8-1:8 expected identifier
|
|
||||||
#else []
|
#else []
|
||||||
|
|
||||||
// Condition must be boolean. If it isn't, neither branch is evaluated.
|
// Condition must be boolean. If it isn't, neither branch is evaluated.
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// Automatically initialized with `none`.
|
// Automatically initialized with `none`.
|
||||||
#let x
|
#let x
|
||||||
[test x, none]
|
#[test x, none]
|
||||||
|
|
||||||
// Initialized with `1`.
|
// Initialized with `1`.
|
||||||
#let y = 1
|
#let y = 1
|
||||||
[test y, 1]
|
#[test y, 1]
|
||||||
|
|
||||||
// Initialize with template, not terminated by semicolon in template.
|
// Initialize with template, not terminated by semicolon in template.
|
||||||
#let v = [Hello; there]
|
#let v = [Hello; there]
|
||||||
@ -15,10 +15,10 @@
|
|||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
)
|
)
|
||||||
[test x, (1, 2, 3)]
|
#[test x, (1, 2, 3)]
|
||||||
|
|
||||||
// Multiple bindings in one line.
|
// Multiple bindings in one line.
|
||||||
#let x = "a"; #let y = "b"; [test x + y, "ab"]
|
#let x = "a"; #let y = "b"; #[test x + y, "ab"]
|
||||||
|
|
||||||
// Invalid name.
|
// Invalid name.
|
||||||
// Error: 1:6-1:7 expected identifier, found integer
|
// Error: 1:6-1:7 expected identifier, found integer
|
||||||
@ -43,24 +43,24 @@ The Fi#let;rst
|
|||||||
|
|
||||||
// Terminated with just a line break.
|
// Terminated with just a line break.
|
||||||
#let v = "a"
|
#let v = "a"
|
||||||
The Second [test v, "a"]
|
The Second #[test v, "a"]
|
||||||
|
|
||||||
// Terminated with semicolon + line break.
|
// Terminated with semicolon + line break.
|
||||||
#let v = "a";
|
#let v = "a";
|
||||||
The Third [test v, "a"]
|
The Third #[test v, "a"]
|
||||||
|
|
||||||
// Terminated with just a semicolon.
|
// Terminated with just a semicolon.
|
||||||
The#let v = "a"; Fourth [test v, "a"]
|
The#let v = "a"; Fourth #[test v, "a"]
|
||||||
|
|
||||||
// Terminated by semicolon even though we are in a paren group.
|
// Terminated by semicolon even though we are in a paren group.
|
||||||
// Error: 2:25-2:25 expected expression
|
// Error: 2:25-2:25 expected expression
|
||||||
// Error: 1:25-1:25 expected closing paren
|
// Error: 1:25-1:25 expected closing paren
|
||||||
The#let array = (1, 2 + ;Fifth [test array, (1, 2)]
|
The#let array = (1, 2 + ;Fifth #[test array, (1, 2)]
|
||||||
|
|
||||||
// Not terminated.
|
// Not terminated.
|
||||||
// Error: 1:16-1:16 expected semicolon or line break
|
// Error: 1:16-1:16 expected semicolon or line break
|
||||||
The#let v = "a"Sixth [test v, "a"]
|
The#let v = "a"Sixth #[test v, "a"]
|
||||||
|
|
||||||
// Not terminated.
|
// Not terminated.
|
||||||
// Error: 1:16-1:16 expected semicolon or line break
|
// Error: 1:16-1:16 expected semicolon or line break
|
||||||
The#let v = "a" [test v, "a"] Seventh
|
The#let v = "a" #[test v, "a"] Seventh
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
[font 8pt]
|
#[font 8pt]
|
||||||
|
|
||||||
// Typst syntax inside.
|
// Typst syntax inside.
|
||||||
`#let x = 1``[f 1]`
|
`#let x = 1``[f 1]`
|
||||||
|
@ -37,4 +37,4 @@
|
|||||||
{"a\n[]\"\u{1F680}string"} \
|
{"a\n[]\"\u{1F680}string"} \
|
||||||
|
|
||||||
// Templates.
|
// Templates.
|
||||||
{[*{"Hi"} [f 1]*]}
|
{[*{"Hi"} #[f 1]*]}
|
||||||
|
@ -1,37 +1,37 @@
|
|||||||
// Test configuring font properties.
|
// Test configuring font properties.
|
||||||
|
|
||||||
[font "PT Sans", 10pt]
|
#[font "PT Sans", 10pt]
|
||||||
|
|
||||||
// Set same font size in three different ways.
|
// Set same font size in three different ways.
|
||||||
[font 20pt][A]
|
#[font 20pt][A]
|
||||||
[font 200%][A]
|
#[font 200%][A]
|
||||||
[font 15pt + 50%][A]
|
#[font 15pt + 50%][A]
|
||||||
|
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
[font][Normal]
|
#[font][Normal]
|
||||||
|
|
||||||
// Set style (is available).
|
// Set style (is available).
|
||||||
[font style: italic][Italic]
|
#[font style: italic][Italic]
|
||||||
|
|
||||||
// Set weight (is available).
|
// Set weight (is available).
|
||||||
[font weight: bold][Bold]
|
#[font weight: bold][Bold]
|
||||||
|
|
||||||
// Set stretch (not available, matching closest).
|
// Set stretch (not available, matching closest).
|
||||||
[font stretch: ultra-condensed][Condensed]
|
#[font stretch: ultra-condensed][Condensed]
|
||||||
|
|
||||||
// Error: 1:7-1:12 unexpected argument
|
// Error: 1:8-1:13 unexpected argument
|
||||||
[font false]
|
#[font false]
|
||||||
|
|
||||||
// Error: 3:14-3:18 expected font style, found font weight
|
// Error: 3:15-3:19 expected font style, found font weight
|
||||||
// Error: 2:28-2:34 expected font weight, found string
|
// Error: 2:29-2:35 expected font weight, found string
|
||||||
// Error: 1:43-1:44 expected font family or array of font families, found integer
|
// Error: 1:44-1:45 expected font family or array of font families, found integer
|
||||||
[font style: bold, weight: "thin", serif: 0]
|
#[font style: bold, weight: "thin", serif: 0]
|
||||||
|
|
||||||
// Warning: 1:15-1:19 should be between 100 and 900
|
// Warning: 1:16-1:20 should be between 100 and 900
|
||||||
[font weight: 2700]
|
#[font weight: 2700]
|
||||||
|
|
||||||
// Error: 1:7-1:27 unexpected argument
|
// Error: 1:8-1:28 unexpected argument
|
||||||
[font something: "invalid"]
|
#[font something: "invalid"]
|
||||||
|
|
||||||
---
|
---
|
||||||
// Test font fallback and class definitions.
|
// Test font fallback and class definitions.
|
||||||
@ -40,17 +40,17 @@
|
|||||||
Emoji: 🏀
|
Emoji: 🏀
|
||||||
|
|
||||||
// CMU Serif + Noto Emoji.
|
// CMU Serif + Noto Emoji.
|
||||||
[font "CMU Serif", "Noto Emoji"][
|
#[font "CMU Serif", "Noto Emoji"][
|
||||||
Emoji: 🏀
|
Emoji: 🏀
|
||||||
]
|
]
|
||||||
|
|
||||||
// Class definitions.
|
// Class definitions.
|
||||||
[font serif: ("CMU Serif", "Latin Modern Math", "Noto Emoji")]
|
#[font serif: ("CMU Serif", "Latin Modern Math", "Noto Emoji")]
|
||||||
[font serif][
|
#[font serif][
|
||||||
Math: ∫ α + β ➗ 3
|
Math: ∫ α + β ➗ 3
|
||||||
]
|
]
|
||||||
|
|
||||||
// Class definition reused.
|
// Class definition reused.
|
||||||
[font sans-serif: "Noto Emoji"]
|
#[font sans-serif: "Noto Emoji"]
|
||||||
[font sans-serif: ("Archivo", sans-serif)]
|
#[font sans-serif: ("Archivo", sans-serif)]
|
||||||
New sans-serif. 🚀
|
New sans-serif. 🚀
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
// Ends paragraphs.
|
// Ends paragraphs.
|
||||||
Tightly [v -5pt] packed
|
Tightly #[v -5pt] packed
|
||||||
|
|
||||||
// Eating up soft spacing.
|
// Eating up soft spacing.
|
||||||
Inv [h 0pt] isible
|
Inv #[h 0pt] isible
|
||||||
|
|
||||||
// Multiple spacings in a row.
|
// Multiple spacings in a row.
|
||||||
Add [h 10pt] [h 10pt] up
|
Add #[h 10pt] #[h 10pt] up
|
||||||
|
|
||||||
// Relative to font size.
|
// Relative to font size.
|
||||||
Relative [h 100%] spacing
|
Relative #[h 100%] spacing
|
||||||
|
|
||||||
// Missing spacing.
|
// Missing spacing.
|
||||||
// Error: 1:11-1:11 missing argument: spacing
|
// Error: 1:12-1:12 missing argument: spacing
|
||||||
Totally [h] ignored
|
Totally #[h] ignored
|
||||||
|
|
||||||
// Swapped axes.
|
// Swapped axes.
|
||||||
[page main-dir: rtl, cross-dir: ttb, height: 80pt][
|
#[page main-dir: rtl, cross-dir: ttb, height: 80pt][
|
||||||
1 [h 1cm] 2
|
1 #[h 1cm] 2
|
||||||
|
|
||||||
3 [v 1cm] 4 [v -1cm] 5
|
3 #[v 1cm] 4 #[v -1cm] 5
|
||||||
]
|
]
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
// Test loading different image formats.
|
// Test loading different image formats.
|
||||||
|
|
||||||
// Load an RGBA PNG image.
|
// Load an RGBA PNG image.
|
||||||
[image "res/rhino.png"]
|
#[image "res/rhino.png"]
|
||||||
[pagebreak]
|
#[pagebreak]
|
||||||
|
|
||||||
// Load an RGB JPEG image.
|
// Load an RGB JPEG image.
|
||||||
[image "res/tiger.jpg"]
|
#[image "res/tiger.jpg"]
|
||||||
|
|
||||||
// Error: 1:8-1:29 failed to load image
|
// Error: 1:9-1:30 failed to load image
|
||||||
[image "path/does/not/exist"]
|
#[image "path/does/not/exist"]
|
||||||
|
|
||||||
// Error: 1:8-1:29 failed to load image
|
// Error: 1:9-1:30 failed to load image
|
||||||
[image "typ/image-error.typ"]
|
#[image "typ/image-error.typ"]
|
||||||
|
|
||||||
---
|
---
|
||||||
// Test configuring the size and fitting behaviour of images.
|
// Test configuring the size and fitting behaviour of images.
|
||||||
|
|
||||||
// Fit to width of page.
|
// Fit to width of page.
|
||||||
[image "res/rhino.png"]
|
#[image "res/rhino.png"]
|
||||||
|
|
||||||
// Fit to height of page.
|
// Fit to height of page.
|
||||||
[page height: 40pt][
|
#[page height: 40pt][
|
||||||
[image "res/rhino.png"]
|
#[image "res/rhino.png"]
|
||||||
]
|
]
|
||||||
|
|
||||||
// Set width explicitly.
|
// Set width explicitly.
|
||||||
[image "res/rhino.png", width: 50pt]
|
#[image "res/rhino.png", width: 50pt]
|
||||||
|
|
||||||
// Set height explicitly.
|
// Set height explicitly.
|
||||||
[image "res/rhino.png", height: 50pt]
|
#[image "res/rhino.png", height: 50pt]
|
||||||
|
|
||||||
// Set width and height explicitly and force stretching.
|
// Set width and height explicitly and force stretching.
|
||||||
[image "res/rhino.png", width: 25pt, height: 50pt]
|
#[image "res/rhino.png", width: 25pt, height: 50pt]
|
||||||
|
|
||||||
// Make sure the bounding-box of the image is correct.
|
// Make sure the bounding-box of the image is correct.
|
||||||
[align bottom, right][
|
#[align bottom, right][
|
||||||
[image "res/tiger.jpg", width: 60pt]
|
#[image "res/tiger.jpg", width: 60pt]
|
||||||
]
|
]
|
||||||
|
@ -1,54 +1,53 @@
|
|||||||
// Test configuring page sizes and margins.
|
// Test configuring page sizes and margins.
|
||||||
|
|
||||||
// Set width and height.
|
// Set width and height.
|
||||||
[page width: 120pt, height: 120pt]
|
#[page width: 120pt, height: 120pt]
|
||||||
[page width: 40pt][High]
|
#[page width: 40pt][High]
|
||||||
[page height: 40pt][Wide]
|
#[page height: 40pt][Wide]
|
||||||
|
|
||||||
// Set all margins at once.
|
// Set all margins at once.
|
||||||
[page margins: 30pt][
|
#[page margins: 30pt][
|
||||||
[align top, left][TL]
|
#[align top, left][TL]
|
||||||
[align bottom, right][BR]
|
#[align bottom, right][BR]
|
||||||
]
|
]
|
||||||
|
|
||||||
// Set individual margins.
|
// Set individual margins.
|
||||||
[page height: 40pt]
|
#[page height: 40pt]
|
||||||
[page left: 0pt | align left][Left]
|
#[page left: 0pt | align left][Left]
|
||||||
[page right: 0pt | align right][Right]
|
#[page right: 0pt | align right][Right]
|
||||||
[page top: 0pt | align top][Top]
|
#[page top: 0pt | align top][Top]
|
||||||
[page bottom: 0pt | align bottom][Bottom]
|
#[page bottom: 0pt | align bottom][Bottom]
|
||||||
|
|
||||||
// Ensure that specific margins override general margins.
|
// Ensure that specific margins override general margins.
|
||||||
[page margins: 0pt, left: 20pt][Overriden]
|
#[page margins: 0pt, left: 20pt][Overriden]
|
||||||
|
|
||||||
// Error: 1:7-1:18 unknown variable
|
// Error: 1:8-1:19 unknown variable
|
||||||
[page nonexistant]
|
#[page nonexistant]
|
||||||
|
|
||||||
// Error: 1:17-1:20 aligned axis
|
// Error: 1:18-1:21 aligned axis
|
||||||
[page main-dir: ltr]
|
#[page main-dir: ltr]
|
||||||
|
|
||||||
// Flipped predefined paper.
|
// Flipped predefined paper.
|
||||||
[page "a11", flip: true][Flipped A11]
|
#[page "a11", flip: true][Flipped A11]
|
||||||
|
|
||||||
// Flipped custom page size.
|
// Flipped custom page size.
|
||||||
[page width: 40pt, height: 120pt]
|
#[page width: 40pt, height: 120pt]
|
||||||
[page flip: true]
|
#[page flip: true]
|
||||||
Wide
|
Wide
|
||||||
|
|
||||||
// Test changing the layouting directions of pages.
|
// Test changing the layouting directions of pages.
|
||||||
|
#[page height: 50pt, main-dir: btt, cross-dir: rtl]
|
||||||
[page height: 50pt, main-dir: btt, cross-dir: rtl]
|
|
||||||
Right to left!
|
Right to left!
|
||||||
|
|
||||||
---
|
---
|
||||||
// Test a combination of pages with bodies and normal content.
|
// Test a combination of pages with bodies and normal content.
|
||||||
|
|
||||||
[page height: 50pt]
|
#[page height: 50pt]
|
||||||
|
|
||||||
[page][First]
|
#[page][First]
|
||||||
[page][Second]
|
#[page][Second]
|
||||||
[pagebreak]
|
#[pagebreak]
|
||||||
Fourth
|
Fourth
|
||||||
[page][]
|
#[page][]
|
||||||
Sixth
|
Sixth
|
||||||
[page][Seventh and last]
|
#[page][Seventh and last]
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
First of two
|
First of two
|
||||||
[pagebreak]
|
#[pagebreak]
|
||||||
[page height: 40pt]
|
#[page height: 40pt]
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
// Check the output.
|
// Check the output.
|
||||||
[rgb 0.0, 0.3, 0.7]
|
#[rgb 0.0, 0.3, 0.7]
|
||||||
|
|
||||||
// Alpha channel.
|
// Alpha channel.
|
||||||
[rgb 1.0, 0.0, 0.0, 0.5]
|
#[rgb 1.0, 0.0, 0.0, 0.5]
|
||||||
|
|
||||||
// Warning: 2:6-2:9 should be between 0.0 and 1.0
|
// Warning: 2:7-2:10 should be between 0.0 and 1.0
|
||||||
// Warning: 1:11-1:15 should be between 0.0 and 1.0
|
// Warning: 1:12-1:16 should be between 0.0 and 1.0
|
||||||
[rgb -30, 15.5, 0.5]
|
#[rgb -30, 15.5, 0.5]
|
||||||
|
|
||||||
// Error: 1:6-1:10 missing argument: blue component
|
// Error: 1:7-1:11 missing argument: blue component
|
||||||
[rgb 0, 1]
|
#[rgb 0, 1]
|
||||||
|
|
||||||
// Error: 3:5-3:5 missing argument: red component
|
// Error: 3:6-3:6 missing argument: red component
|
||||||
// Error: 2:5-2:5 missing argument: green component
|
// Error: 2:6-2:6 missing argument: green component
|
||||||
// Error: 1:5-1:5 missing argument: blue component
|
// Error: 1:6-1:6 missing argument: blue component
|
||||||
[rgb]
|
#[rgb]
|
||||||
|
Loading…
Reference in New Issue
Block a user