solang icon indicating copy to clipboard operation
solang copied to clipboard

"unrecognised token '.' when "if (error.length > 0)"

Open yg0x01 opened this issue 3 years ago • 4 comments

I try to use solang-parser to parse some contract and found "unrecognised token '.' error.

This sample contract code can trigger this issue:

pragma solidity 0.6.12;

contract A {
    address init;

    constructor(address init_addr) {
        init = init_addr;
    }

    function f(bytes calldata _calldata) public {
        (bool success, bytes memory error) = _init.delegatecall(_calldata);
        if (!success) {
            if (error.length > 0) {
                revert(string(error));
            } else {
                revert("aa");
            }
        }
    }
}
"unrecognised token '.', expected \"!=\", \"%\", \"%=\", \"&\", \"&&\", \"&=\", \")\", \"*\", \"**\", \"*=\", \"+\", \"+=\", \",\", \"-\", \"-=\", \"/\", \"/=\", \":\", \";\", \"<\", \"<<\", \"<<=\", \"<=\", \"=\", \"==\", \">\", \">=\", \">>\", \">>=\", \"?\", \"]\", \"^\", \"^=\", \"calldata\", \"case\", \"default\", \"error\", \"leave\", \"memory\", \"revert\", \"storage\", \"switch\", \"|\", \"|=\", \"||\", \"}\", identifier"

and I found the error range is:

if (error.length > 0) {

It seems like solang-parser does not properly parse this error.length?

yg0x01 avatar Jul 26 '22 14:07 yg0x01

oh, error is the keyword of solidity, I got it.

yg0x01 avatar Jul 26 '22 14:07 yg0x01

Emm... I found that the keyword "error" can be a legal variable name.

pragma solidity ^0.8.0;

contract A {
    address init;

    constructor(address init_addr) {
        init = init_addr;
    }

    function f(bytes calldata _calldata) public {
        (bool success, bytes memory error) = init.delegatecall(_calldata);
        if (!success) {
            if (error.length > 0) {
                revert(string(error));
            } else {
                revert("aa");
            }
        }
    }
}

This sample code can be compiled successfully. So I think we should reopen this issue.

I try to fix it by adding a special case in solidity.lalrpop. But I don't know if this will have other effects.

NoFunctionTyPrecedence0: Expression = {
    <a:@L> <e:Precedence0> "++" <b:@R> => Expression::PostIncrement(Loc::File(file_no, a, b), Box::new(e)),
    <a:@L> <e:Precedence0> "--" <b:@R> => Expression::PostDecrement(Loc::File(file_no, a, b), Box::new(e)),
    <FunctionCall> => <>,
    <a:@L> <e:Precedence0> "[" <i:Expression?> "]" <b:@R> => Expression::ArraySubscript(Loc::File(file_no, a, b), Box::new(e), i.map(Box::new)),
    <a:@L> <e:Precedence0> "[" <l:Expression?> ":" <r:Expression?> "]" <b:@R> => Expression::ArraySlice(Loc::File(file_no, a, b), Box::new(e), l.map(Box::new), r.map(Box::new)),
    <a:@L> <e:Precedence0> "." <i:SolIdentifier> <b:@R> => Expression::MemberAccess(Loc::File(file_no, a, b), Box::new(e), i),
    <a:@L> "error" <al:@L> "." <i:SolIdentifier> <b:@R> => Expression::MemberAccess(Loc::File(file_no, a, b), Box::new(Expression::Variable(Identifier { loc: Loc::File(file_no, a, al), name: "error".to_string()})), i),
    // Solidity has ".address" members on external function types. Address is a keyword, so special casing needed
    <a:@L> <e:Precedence0> "." <al:@L> "address" <b:@R> => {
        Expression::MemberAccess(Loc::File(file_no, a, b), Box::new(e),
            Identifier { loc: Loc::File(file_no, al, b), name: "address".to_string() })
    },

<a:@L> "error" al:@L "." <i:SolIdentifier> <b:@R> => Expression::MemberAccess(Loc::File(file_no, a, b), Box::new(Expression::Variable(Identifier { loc: Loc::File(file_no, a, al), name: "error".to_string()})), i),

Maybe have any better solutions? I'm not very familiar with lalrpop. Thanks.

yg0x01 avatar Jul 27 '22 03:07 yg0x01

You are right: in solc, error is not a keyword, even though it can be used for declaring error definitions using error Foo(int);.

The way to fix this is to add:

    <l:@L> "error" <r:@R> => Identifier{loc: Loc::File(file_no, l, r), name: "error".to_string()},

Unfortunately this makes the grammar ambiguous which is not permitted in lalrpop.

seanyoung avatar Jul 27 '22 08:07 seanyoung

This is quite a tricky issue to solve with lalrpop :disappointed:

seanyoung avatar Jul 27 '22 08:07 seanyoung

@seanyoung Above contract compiles fine for the substrate target, I conclude that this has been solved in the meantime.

xermicus avatar Jun 29 '23 10:06 xermicus