0

EDIT: It turns out that the Rust compiler is not smart enough to carry over information about whether or not a variable was statically defined. At the point when you pattern match, the compiler only knows that its a String.

I am trying to make a parser in Rust and I have already defined a Token enum as so.

pub enum Constant {
    String(String),
}

pub enum Token {
    KwIf,
    KwThen,
    KwElse,
    Constant(Constant),
}

I have also written a literal function, the important bit is that this function returns static strings (i.e. &'static str), because of performance reasons (the strings will also never change so it makes sense for them to be constant throughout the lifetime of the program).

impl Token {
    pub fn literal(&self) ->  Option<&'static str> {
        match self {
            &Token::KwIf => Some("if"),
            &Token::KwThen => Some("then"),
            &Token::KwElse => Some("else"),
            _ => None,
        }
    }
}

The issue I have right now is how would you pattern match against the literal function and use the rust print! function to directly print the literal string, i.e. assuming I write something like this

use Constant::*;
pub fn print_token(token: Token) {
    match token.literal() {
        Some(literal) => print!(literal);
        None => match token {
            Token::Constant(constant) => match constant {
                String(string) => print!("{}", string),
                _ => panic!("Unexpected token"),
            }
        }
    }
}

The issue is that I get a compile error when I try to print this literal, i.e. the compile error I get is error: format argument must be a string literal. I have tried many combinations of how to print the static string literal without having to cast it to a normal String (which of course defeats the purpose of using a static string literal in the first place).

Alternately is there a better way to approach the problem I am trying to solve, I am making a parser for a language and as can be soon, I am coding up the tokens as well parser/printer.

mdedetrich
  • 1,899
  • 1
  • 18
  • 29

1 Answers1

2

I think that the problem is this line

Some(literal) => print!(literal);

It should be

Some(literal) => print!("{}", literal),

The same as you've done in the None case.

I believe println! uses the format! macro and according to the rust docs

"The first argument format! receives is a format string. This must be a string literal."

https://doc.rust-lang.org/std/macro.format.html

Nuchs
  • 285
  • 3
  • 4
  • I understand that you can do `Some(literal) => print!("{}", literal),`, the thing is that the `literal` value is a string static literal and `print!(literal)` should therefore work. Unless I am mistaken, if you do `print!("{}",literal)`, this defeats the point of using string static literals in the first place as it will have worst performance (since you are going to be casting the string static literal to a normal string). To be clear, if you don't use `Option` the code works fine, `print!(literal)` will work since the compiler can infer its a static string literal. – mdedetrich Mar 03 '18 at 15:01
  • Are you sure that works? I tried ```let f = "Hello"; println!(f); ``` and got 'error: expected a literal'. As far as I'm aware a literal is the actual value appearing in the source code. In your match statement you create a new binding called literal but its not actually a literal value, hence the error. – Nuchs Mar 03 '18 at 15:25
  • 1
    @mdedetrich `literal` is not a literal. Read e.g. [println! error: expected a literal / format argument must be a string literal](https://stackoverflow.com/questions/27734708/println-error-expected-a-literal-format-argument-must-be-a-string-literal?noredirect=1&lq=1) and [What does the word “literal” mean?](https://stackoverflow.com/questions/485119/what-does-the-word-literal-mean?noredirect=1&lq=1) – trent Mar 03 '18 at 15:31
  • Thanks for the links, I realized the Rust compiler isn't smart enough to figure out that its still a static literal string. The rust compiler does carry over type information in the AST, but not whether the variable was statically defined as a literal. – mdedetrich Mar 03 '18 at 16:31
  • @mdedetrich The format parameter to `print!` is effectively code (a domain specific language), not data. The `print!` macro generates different code depending on its value, i.e. it is a compiler that translates the DSL to rust. So there must only be one possible DSL program for each macro expansion of `print!`. – CodesInChaos Mar 03 '18 at 17:37