Module lang

Module lang 

Source
Expand description

§Boxworks language

This module defines a domain-specific language (DSL) for Boxworks. This language is used to describe Boxworks elements in Knuth’s box-and-glue model. The initial motivation for the language is to make it easy to create Boxworks primitives, like horizontal and vertical lists, for use in unit testing.

In the long run, the language will probably support running the Boxworks engine and actually performing typesetting. If this happens, this language will be a sort of “intermediate representation” for the Texcraft project.

This is a basic example of converting some of the language into a horizontal list:

use boxworks::ds;
use boxworks::lang as bwl;

let source = r#"
    # The chars() function typesets characters.
    chars("Box")
    # Glue can be added manually.
    glue(1pt, 5fil, 0.075in)
    # The following elements illustrate the prototypical example of a kern.
    chars("A")
    kern(-0.1pt)
    chars("V")
"#;
let got = bwl::parse_horizontal_list(&source);
let want: Vec<ds::Horizontal> = vec![
    ds::Char{char: 'B', font: 0}.into(),
    ds::Char{char: 'o', font: 0}.into(),
    ds::Char{char: 'x', font: 0}.into(),
    ds::Glue{
        kind: ds::GlueKind::Normal,
        value: common::Glue{
            width: common::Scaled::new(
                1,  // integer part
                common::Scaled::ZERO,  // fractional part
                common::ScaledUnit::Point,  // units
            ).unwrap(),
            stretch: common::Scaled::new(
                5,  // integer part
                common::Scaled::ZERO,  // fractional part
                common::ScaledUnit::Point,  // units
            ).unwrap(),
            stretch_order: common::GlueOrder::Fil,
            shrink: common::Scaled::new(
                0,  // integer part
                common::Scaled::from_decimal_digits(&[0, 7, 5]),  // fractional part
                common::ScaledUnit::Inch,  // units
            ).unwrap(),
            shrink_order: common::GlueOrder::Normal,
        }
    }.into(),
    ds::Char{char: 'A', font: 0}.into(),
    ds::Kern{
        kind: ds::KernKind::Normal,
        width: -common::Scaled::new(
                0,  // integer part
                common::Scaled::from_decimal_digits(&[1]),  // fractional part
                common::ScaledUnit::Point,  // units
            ).unwrap(),
    }.into(),
    ds::Char{char: 'V', font: 0}.into(),
];
assert_eq![got, Ok(want)];

The main takeaway from this example is that you start with a very terse description of the horizontal list, and the library outputs the long and tedious Rust struct definitions.

§Language specification

A Boxworks language program is a sequence of a function calls like chars("ABC") or glue(10pt, 3pt, 2pt). Most function calls add an item or items to the current box-and-glue list.

§Function arguments

Each function accepts a number of arguments. For simplicity, every argument to every function is optional.

Arguments can be provided positionally:

let source = r#"
    chars("A", 1)
"#;
assert_eq![
    bwl::parse_horizontal_list(&source),
    Ok(vec![ds::Char{char: 'A', font: 1}.into()])
];

Or by keyword, potentially out of order:

let source = r#"
    chars(font=2, content="B")
"#;
assert_eq![
    bwl::parse_horizontal_list(&source),
    Ok(vec![ds::Char{char: 'B', font: 2}.into()])
];

Or by a combination of positional and by keyword:

let source = r#"
    chars("C", font=3)
"#;
assert_eq![
    bwl::parse_horizontal_list(&source),
    Ok(vec![ds::Char{char: 'C', font: 3}.into()])
];

However, all positional arguments must be provided before keyword arguments:

let source = r#"
    chars(content="C", 3)
"#;
let errs = bwl::parse_horizontal_list(&source).unwrap_err();
assert![matches![
    errs[0],
    bwl::Error::PositionalArgAfterKeywordArg{..}
]];

§Function argument types

Every function argument expects a specific concrete type. These are the types:

NameDescriptionExamples
StringArbitrary UTF-8 characters between double quotes. Currently the string can’t contain a double quote character."a string"
IntegerDecimal integer in the range (-2^31,2^31).123, -456
DimensionDecimal number with a unit attached. The format and the allowable units are the same as in TeX.1pt, 2.04in, -10sp
Glue stretch or shrinkA dimension where the unit can alternatively be an infinite stretch/shrink unit.1fil, -2fill, 3filll
CharacterA string containing exactly one UTF-8 character."A", "ñ"
Glue orderOne of the strings "normal", "fil", "fill", or "filll"."normal", "fill"
Glue ratioA floating-point number represented as a string."1.5", "-0.25"
Dimension or runningEither a dimension, or the string "running" to indicate the value is determined by context.1pt, "running"
Horizontal listA bracket-enclosed list of horizontal-mode function calls.[chars("Hi") glue()]
Vertical listA bracket-enclosed list of vertical-mode function calls.[glue() kern(1pt)]
Discretionary listA bracket-enclosed list of function calls valid in discretionary pre/post-break lists.[chars("-") kern(0.5pt)]

§Available functions

More functions will be added over time. These are the currently supported functions.

§chars: typeset some characters

Adds a value of the Rust type super::ds::Char for each character in the input string.

Only available in horizontal and discretionary lists, not vertical lists.

Parameters:

NumberNameTypeDefault
1contentstring""
2fontinteger0
§glue: add a glue node to the current list

Adds a value of the Rust type super::ds::Glue to the current list.

Only available in horizontal and vertical lists, not discretionary lists.

Parameters:

NumberNameTypeDefault
1widthdimension0pt
2stretchglue stretch or shrink0pt
3shrinkglue stretch or shrink0pt
§penalty: add a penalty node to the current list

Adds a value of the Rust type super::ds::Penalty to the current list.

Only available in horizontal and vertical lists, not discretionary lists.

Parameters:

NumberNameTypeDefault
1valueinteger0
§kern: add a kern node to the current list

Adds a value of the Rust type super::ds::Kern to the current list.

Parameters:

NumberNameTypeDefault
1widthdimension0pt
§hbox: add a horizontal box to the current list

Adds a value of the Rust type super::ds::HBox to the current list.

Parameters:

NumberNameTypeDefault
1heightdimension0pt
2widthdimension0pt
3depthdimension0pt
4shift_amountdimension0pt
5glue_ratioglue ratio"0.0"
6glue_orderglue order"normal"
7contenthorizontal list[]
§lig: add a ligature node to the current list

Adds a value of the Rust type super::ds::Ligature to the current list.

Only available in horizontal and discretionary lists, not vertical lists.

Parameters:

NumberNameTypeDefault
1charcharacter"\0"
2original_charsstring""
3fontinteger0
§vbox: add a vertical box to the current list

Adds a value of the Rust type super::ds::VBox to the current list.

Parameters:

NumberNameTypeDefault
1heightdimension0pt
2widthdimension0pt
3depthdimension0pt
4shift_amountdimension0pt
5contentvertical list[]
§disc: add a discretionary node to the current list

Adds a value of the Rust type super::ds::Discretionary to the current list.

Only available in horizontal lists.

Parameters:

NumberNameTypeDefault
1pre_breakdiscretionary list[]
2post_breakdiscretionary list[]
3replace_countinteger0
§rule: add a rule to the current list

Adds a value of the Rust type super::ds::Rule to the current list.

Parameters:

NumberNameTypeDefault
1heightdimension or running0pt
2widthdimension or running0pt
3depthdimension or running0pt
§mark: add a mark node to the current list

Adds a value of the Rust type super::ds::Mark to the current list.

Only available in horizontal and vertical lists, not discretionary lists.

Parameters: none.

§adjust: add an adjust node to the current list

Adds a value of the Rust type super::ds::Adjust to the current list.

Only available in horizontal lists.

Parameters:

NumberNameTypeDefault
1contentvertical list[]
§insertion: add an insertion node to the current list

Adds a value of the Rust type super::ds::Insertion to the current list.

Only available in horizontal and vertical lists, not discretionary lists.

Parameters:

NumberNameTypeDefault
1box_numberinteger0
2heightdimension0pt
3split_max_depthdimension0pt
4split_top_skip_widthdimension0pt
5split_top_skip_stretchglue stretch or shrink0pt
6split_top_skip_shrinkglue stretch or shrink0pt
7float_penaltyinteger0
8vboxvertical list[]
§math: add a math node to the current list

Adds a value of the Rust type super::ds::Math to the current list.

Only available in horizontal and vertical lists, not discretionary lists.

Parameters:

NumberNameTypeDefault
1kindstring""

Modules§

ast
Box language abstract syntax tree
convert
Conversions between Box language and Boxworks data structures
cst
Box language concrete syntax tree (CST).
lexer
Lexer and tokens for Box language.

Structs§

ErrorAccumulator
A data structure for accumulating errors.
ErrorLabel
Label on an error message.
Str
String type used in the crate’s public API.

Enums§

Error
Error encountered when parsing Box language.

Functions§

format
Pretty-format Box source code.
parse_horizontal_list
Parse Box language source code into a horizontal list.