Error: no rules expected the token `"this is a string"`

Compiling pwasm contract to run string. Since pwasm-abi wont support String type I used Vec<u8> type. Main part of my code

fn sayHello(&mut self) -> Vec<u8> {
        vec![];
            #[macro_use]
            mod vec {
            macro_rules! vec {
                () => ()
            }
        }   
        let s: Vec<u8> = vec!["this is a string"];
        let tests = String::from_utf8(s).unwrap();
        assert_eq!(s, tests);
        }

It gives me an error

error: no rules expected the token `"this is a string"`
  --> src/lib.rs:47:31
   |
47 |         let s: Vec<u8> = vec!["this is a string"];
   |                               ^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Any idea to solve this error

You redefined the vec! macro into one that takes no arguments and produces nothing. That first line of vec![]; also does nothing.

Why did you do that?

3 Likes

I've re-written your code to be correctly indented:

fn sayHello(&mut self) -> Vec<u8> {
    vec![];
    #[macro_use]
    mod vec {
        macro_rules! vec {
            () => ()
        }
    }   
    let s: Vec<u8> = vec!["this is a string"];
    let tests = String::from_utf8(s).unwrap();
    assert_eq!(s, tests);
}

Your code does the following:

// Define a function (that must be inside an `impl` block), that takes a mut ref to self and 
// returns a vec of bytes.
fn sayHello(&mut self) -> Vec<u8> {
    // Create an empty Vec and immediately discard it (it isn't assigned to anything). The compiler can
    // remove this line without affecting the result of the code
    vec![];
    // Create a new module, but import macros from it into our namespace
    #[macro_use]
    mod vec {
        // Create a macro that must be called like `vec![]` (no arguments), and will collapse to ().
        macro_rules! vec {
            () => ()
        }
    }
    // Try to use the above macro, which has overwritten the `vec!` macro from the standard library,
    // This will error since the only way to call your vec is `vec![]`.
    let s: Vec<u8> = vec!["this is a string"];
    // This will also error as `s` hasn't been defined.
    let tests = String::from_utf8(s).unwrap();
    assert_eq!(s, tests);
}

We can probably help fix your code, if you tell us what you are trying to accomplish.

1 Like

@ derekdreery
To be more clear am compiling rust contract in parity client (i.e pwasm) to run string function.
I have attached my complete code

#![no_std]
#![allow(non_snake_case)]
#![feature(alloc)]
#![feature(use_extern_macros)]
#![feature(proc_macro_gen)]

extern crate pwasm_std;
extern crate pwasm_ethereum;
extern crate pwasm_abi;
extern crate pwasm_abi_derive;
extern crate std;

pub mod hello {
    use pwasm_ethereum;
    use pwasm_abi::types::*;
    use std::String;
  
    // eth_abi is a procedural macros https://doc.rust-lang.org/book/first-edition/procedural-macros.html
    use pwasm_abi_derive::eth_abi;

    #[eth_abi(HelloEndpoint)]
    pub trait HelloInterface {
        /// The constructor
        fn constructor(&mut self);
        fn sayHello(&mut self) -> Vec<u8>;
    }

    pub struct HelloContract;
    impl HelloInterface for HelloContract {
        fn constructor (&mut self) {
        }
        
        fn sayHello(&mut self) -> Vec<u8> {

            #[macro_use]
            mod vec {
            macro_rules! vec {
                () => ()
            }
        }   
        let s: Vec<u8> = vec!["this is a string"];
        let tests = String::from_utf8(s).unwrap();
        assert_eq!(s, tests);
        }
    }
}

// Declares the dispatch and dispatch_ctor methods
use pwasm_abi::eth::EndpointInterface;

#[no_mangle]
pub fn call() {
    let mut endpoint = hello::HelloEndpoint::new(hello::HelloContract{});
    
    // Read http://solidity.readthedocs.io/en/develop/abi-spec.html#formal-specification-of-the-encoding for details
    pwasm_ethereum::ret(&endpoint.dispatch(&pwasm_ethereum::input()));
}

#[no_mangle]
pub fn deploy() {
    let mut endpoint = hello::HelloEndpoint::new(hello::HelloContract{});
    //
    endpoint.dispatch_ctor(&pwasm_ethereum::input());
}

Let me know if it required to change code to run

The problem is obvious: you've broken the vec! macro. What we don't understand (and what you haven't answered) is: why did you do that? Why did you replace the standard definition of vec! with one that doesn't do anything? Why did you then put it inside a submodule? Why did you invoke the vec! macro at the start of the function with no elements, and then throw away the result?

4 Likes

I wanted to define my string so I used vec! Cann't I use vec! for string ?
Since I got an error of vec! macro I added it inside the submodule. What is correct way to write this?

vec! is not for creating Strings, it's for creating Vecs. What error did you get?

Also, you said you couldn't return String, so why didn't you create a String and turn that into a Vec?

The problem is that the String type is not supported by the pwasm-abi . Tried to use &[u8] and Vec<u8>
For &[u8] I was getting

error: custom attribute panicked
  --> src/lib.rs:21:5
   |
21 |     #[eth_abi(HelloEndpoint)]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: message: Unable to handle param of type Rptr(None, MutTy { ty: Slice(Path(None, Path { global: false, segments: [PathSegment { ident: Ident("u8"), parameters: AngleBracketed(AngleBracketedParameterData { lifetimes: [], types: [], bindings: [] }) }] })), mutability: Immutable }): not supported by abi

error: aborting due to previous error

So Tried Vec!

error: cannot find macro `vec!` in this scope
  --> src/lib.rs:40:26
   |
40 |         let s: Vec<u8> = vec!["this is a string"];  

To resolve this added

          vec![];
           #[macro_use]
           mod vec {
           macro_rules! vec {
               () => ()
           }
       }  

now am getting error: no rules expected the token "this is a string" `

Writing a #![no_std] crate disables the standard library, including vec! and Vec. But then you do extern crate std; which effectively undoes half of what #![no_std] does. I'm not sure why you did that. However, you didn't then pull in the macros from std (which is where vec! comes from). That would be #[macro_use] extern crate std;.

But then, this appears to be some kind of amalgam of wasm and something else, so I have no idea if that would even work. WebAssembly support is (last I checked) a work in progress. Whatever you're doing appears to add additional constraints on top of that. I assume you have access to allocation, but then I don't know why you're doing #[no_std].

As an aside: you can't just define an empty macro and have it work. That would be like defining an empty function and having the implementation magically fill in somehow. You either pull it in from where it is defined (which in the case of vec! would be std... except maybe for this pwasm thing; I have no idea), or you completely re-implement it yourself.

This really doesn't seem like a good first Rust project... you're making enough errors that you might have more success working through the book, then starting with something simpler. Shore up your understanding of basic Rust before diving head-first into unstable, incomplete features on only partially-supported targets :stuck_out_tongue:

If you do want to continue down this path: change the body of the sayHello function to:

fn sayHello(&mut self) -> Vec<u8> {
    let s = String::from("this is a string");
    let v = Vec::from(s);
    v
}

That said, if String isn't supported, I'm skeptical that Vec will be, since String is really just a Vec in disguise.

I'd probably say that no_std is advanced rust. I'd recommend working through The Rust Book first.

EDIT I've just read the previous comment and it says the same thing. :slight_smile:

Agreed your points. You are telling that the problem is with #![no_std . Yes removing this macro vec! and Vec are working fine.
But pwasm-std is a Parity WASM contracts standard library for Rust. pwasm-std is itself compiled with no_std and expected to be used within no_std-crates/binaries, since it defines lang_item -s on it's own, which will conflict with standard library. Removing no_std affects this.
How can use pwasm-std with Vec now?

I don't understand why you need this, but think the reason you can't use strings in parity is that there is no unicode handling; a binary string converts directly to Vec<u8>, though:

fn sayHello(&mut self) -> Vec<u8> {
    b"this is a string".to_vec();
}

that said, I'm not sure whether ABI endpoints can return a vector either—or only, say Address and U256—if not that explains the #[eth_abi(HelloEndpoint)] compile error !

I guess you followed the pwasm-tutorial?

Looking at the documentation for pwasm-std indicates that it defines both vec! and Vec. So you want to use those instead of the ones from std, along with using #[macro_use] extern crate pwasm_std; to bring the macro in.

BTW wasm32-unknown-unknown supports allocations (i.e. Vec, String, Box, etc.) so you can drop #![no_std] if you'll compile for it.