pub trait Logos<'source>: Sized {
type Extras;
type Source: Source + ?Sized + 'source;
type Error: Default + Clone + PartialEq + Debug + 'source;
// Required method
fn lex(lexer: &mut Lexer<'source, Self>);
// Provided methods
fn lexer(source: &'source Self::Source) -> Lexer<'source, Self> ⓘ
where Self::Extras: Default { ... }
fn lexer_with_extras(
source: &'source Self::Source,
extras: Self::Extras,
) -> Lexer<'source, Self> ⓘ { ... }
}
Expand description
Trait implemented for an enum representing all tokens. You should never have
to implement it manually, use the #[derive(Logos)]
attribute on your enum.
Required Associated Types§
Sourcetype Extras
type Extras
Associated type Extras
for the particular lexer. This can be set using
#[logos(extras = MyExtras)]
and accessed inside callbacks.
Required Methods§
Provided Methods§
Sourcefn lexer(source: &'source Self::Source) -> Lexer<'source, Self> ⓘ
fn lexer(source: &'source Self::Source) -> Lexer<'source, Self> ⓘ
Create a new instance of a Lexer
that will produce tokens implementing
this Logos
.
Examples found in repository?
examples/extras.rs (line 65)
61 62 63 64 65 66 67 68 69 70 71 72
fn main() {
let src = fs::read_to_string(env::args().nth(1).expect("Expected file argument"))
.expect("Failed to read file");
let mut lex = Token::lexer(src.as_str());
while let Some(token) = lex.next() {
if let Ok(Token::Word((line, column))) = token {
println!("Word '{}' found at ({}, {})", lex.slice(), line, column);
}
}
}
More examples
examples/custom_error.rs (line 45)
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
fn main() {
// 256 overflows u8, since u8's max value is 255.
// 'é' is not a valid ascii letter.
let mut lex = Token::lexer("Hello 256 Jérome");
assert_eq!(lex.next(), Some(Ok(Token::Word)));
assert_eq!(lex.slice(), "Hello");
assert_eq!(
lex.next(),
Some(Err(LexingError::InvalidInteger(
"overflow error".to_owned()
)))
);
assert_eq!(lex.slice(), "256");
assert_eq!(lex.next(), Some(Ok(Token::Word)));
assert_eq!(lex.slice(), "J");
assert_eq!(lex.next(), Some(Err(LexingError::NonAsciiCharacter)));
assert_eq!(lex.slice(), "é");
assert_eq!(lex.next(), Some(Ok(Token::Word)));
assert_eq!(lex.slice(), "rome");
assert_eq!(lex.next(), None);
}
examples/json.rs (line 208)
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
fn main() {
let filename = env::args().nth(1).expect("Expected file argument");
let src = fs::read_to_string(&filename).expect("Failed to read file");
let mut lexer = Token::lexer(src.as_str());
match parse_value(&mut lexer) {
Ok(value) => println!("{:#?}", value),
Err((msg, span)) => {
use ariadne::{ColorGenerator, Label, Report, ReportKind, Source};
let mut colors = ColorGenerator::new();
let a = colors.next();
Report::build(ReportKind::Error, &filename, 12)
.with_message("Invalid JSON".to_string())
.with_label(
Label::new((&filename, span))
.with_message(msg)
.with_color(a),
)
.finish()
.eprint((&filename, Source::from(src)))
.unwrap();
}
}
}
examples/json_borrowed.rs (line 204)
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
fn main() {
let filename = env::args().nth(1).expect("Expected file argument");
let src = fs::read_to_string(&filename).expect("Failed to read file");
let mut lexer = Token::lexer(src.as_str());
match parse_value(&mut lexer) {
Ok(value) => println!("{:#?}", value),
Err((msg, span)) => {
use ariadne::{ColorGenerator, Label, Report, ReportKind, Source};
let mut colors = ColorGenerator::new();
let a = colors.next();
Report::build(ReportKind::Error, &filename, 12)
.with_message("Invalid JSON".to_string())
.with_label(
Label::new((&filename, span))
.with_message(msg)
.with_color(a),
)
.finish()
.eprint((&filename, Source::from(src)))
.unwrap();
}
}
}
examples/calculator.rs (line 144)
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
fn main() {
//reads the input expression from the command line
let input = env::args()
.nth(1)
.expect("Expected expression argument (e.g. `1 + 7 * (3 - 4) / 5`)");
//creates a lexer instance from the input
let lexer = Token::lexer(&input);
//splits the input into tokens, using the lexer
let mut tokens = vec![];
for (token, span) in lexer.spanned() {
match token {
Ok(token) => tokens.push(token),
Err(e) => {
println!("lexer error at {:?}: {}", span, e);
return;
}
}
}
//parses the tokens to construct an AST
let ast = match parser().parse(tokens) {
Ok(expr) => {
println!("[AST]\n{:#?}", expr);
expr
}
Err(e) => {
println!("parse error: {:#?}", e);
return;
}
};
//evaluates the AST to get the result
println!("\n[result]\n{}", ast.eval());
}
examples/brainfuck.rs (line 89)
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
pub fn execute(code: &str) {
let operations: Vec<_> = Op::lexer(code).filter_map(|op| op.ok()).collect();
let mut data = [0u8; 30_000]; // Minimum recommended size
let mut pointer: usize = 0;
let len = operations.len();
// We pre-process matching jump commands, and we create
// a mapping between them.
let mut queue = Vec::new();
let mut pairs = HashMap::new();
let mut pairs_reverse = HashMap::new();
for (i, op) in operations.iter().enumerate() {
match op {
Op::CondJumpForward => queue.push(i),
Op::CondJumpBackward => {
if let Some(start) = queue.pop() {
pairs.insert(start, i);
pairs_reverse.insert(i, start);
} else {
panic!(
"Unexpected conditional backward jump at position {}, does not match any '['",
i
);
}
}
_ => (),
}
}
if !queue.is_empty() {
panic!("Unmatched conditional forward jump at positions {:?}, expecting a closing ']' for each of them", queue);
}
/* ANCHOR: fsm */
let mut i: usize = 0;
// True program execution.
loop {
match operations[i] {
Op::IncPointer => pointer += 1,
Op::DecPointer => pointer -= 1,
Op::IncData => data[pointer] = data[pointer].wrapping_add(1),
Op::DecData => data[pointer] = data[pointer].wrapping_sub(1),
Op::OutData => print_byte(data[pointer]),
Op::InpData => data[pointer] = read_byte(),
Op::CondJumpForward => {
if data[pointer] == 0 {
// Skip until matching end.
i = *pairs.get(&i).unwrap();
}
}
Op::CondJumpBackward => {
if data[pointer] != 0 {
// Go back to matching start.
i = *pairs_reverse.get(&i).unwrap();
}
}
}
i += 1;
if i >= len {
break;
}
}
/* ANCHOR_END: fsm */
}
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.