diff options
| author | YongJieYongJie <KhooYongJie@gmx.com> | 2022-03-10 19:14:49 +0800 |
|---|---|---|
| committer | Stephan Seitz <stephan.seitz@fau.de> | 2022-03-11 19:06:39 +0100 |
| commit | a180859eeadd52c05745022064ff423423c17bb5 (patch) | |
| tree | f6f7b234293af53571c8fc294d95bc87a664fba0 | |
| parent | Update lockfile.json (diff) | |
| download | nvim-treesitter-a180859eeadd52c05745022064ff423423c17bb5.tar nvim-treesitter-a180859eeadd52c05745022064ff423423c17bb5.tar.gz nvim-treesitter-a180859eeadd52c05745022064ff423423c17bb5.tar.bz2 nvim-treesitter-a180859eeadd52c05745022064ff423423c17bb5.tar.lz nvim-treesitter-a180859eeadd52c05745022064ff423423c17bb5.tar.xz nvim-treesitter-a180859eeadd52c05745022064ff423423c17bb5.tar.zst nvim-treesitter-a180859eeadd52c05745022064ff423423c17bb5.zip | |
Add highlights query for Solidity
| -rw-r--r-- | lua/nvim-treesitter/parsers.lua | 9 | ||||
| -rw-r--r-- | queries/solidity/highlights.scm | 193 | ||||
| -rw-r--r-- | tests/query/highlights/solidity/test.sol | 173 |
3 files changed, 375 insertions, 0 deletions
diff --git a/lua/nvim-treesitter/parsers.lua b/lua/nvim-treesitter/parsers.lua index 0cd7cab9f..88bf364a4 100644 --- a/lua/nvim-treesitter/parsers.lua +++ b/lua/nvim-treesitter/parsers.lua @@ -959,6 +959,15 @@ list.lalrpop = { maintainers = { "@traxys" }, } +list.solidity = { + install_info = { + url = "https://github.com/YongJieYongJie/tree-sitter-solidity", + branch = "with-generated-c-code", + files = { "src/parser.c" }, + }, + maintainers = { "@YongJieYongJie" }, +} + local M = { list = list, filetype_to_parsername = filetype_to_parsername, diff --git a/queries/solidity/highlights.scm b/queries/solidity/highlights.scm new file mode 100644 index 000000000..2081db8df --- /dev/null +++ b/queries/solidity/highlights.scm @@ -0,0 +1,193 @@ +(comment) @comment +( + (comment) @attribute + (#match? @attribute "^/// .*") +) ;; Handles natspec comments + +; Pragma +(pragma_directive) @tag + + +; Literals +[ + (string) + (hex_string_literal) + (unicode_string_literal) + (yul_string_literal) +] @string +[ + (number_literal) + (yul_decimal_number) + (yul_hex_number) +] @number +[ + (true) + (false) +] @constant.builtin + + +; Type +(type_name) @type +(primitive_type) @type +(contract_declaration name: (identifier) @type) +(struct_declaration struct_name: (identifier) @type) +; (struct_member name: (identifier) @field) ;; Technically correct, but makes highlight worst +(enum_declaration enum_type_name: (identifier) @type) +; Color payable in payable address conversion as type and not as keyword +(payable_conversion_expression "payable" @type) +(emit_statement . (identifier) @type) +; Handles ContractA, ContractB in function foo() override(ContractA, contractB) {} +(override_specifier (identifier) @type) +; Ensures that delimiters in mapping( ... => .. ) are not colored like types +(type_name "(" @punctuation.bracket "=>" @punctuation.delimiter ")" @punctuation.bracket) + + +; Functions and parameters + +(function_definition + function_name: (identifier) @function) +(modifier_definition + name: (identifier) @function) +(yul_evm_builtin) @function.builtin + +; Use contructor coloring for special functions +(constructor_definition "constructor" @constructor) +(fallback_receive_definition "receive" @constructor) +(fallback_receive_definition "fallback" @constructor) + +(modifier_invocation (identifier) @function) + +; Handles expressions like structVariable.g(); +(call_expression . (member_expression (property_identifier) @function.method)) + +; Handles expressions like g(); +(call_expression . (identifier) @function) + +; Handles the field in struct literals like MyStruct({MyField: MyVar * 2}) +(call_expression (identifier) @field . ":") + +; Function parameters +(event_paramater name: (identifier) @variable.parameter) +(function_definition + function_name: (identifier) @variable.parameter) + +; Yul functions +(yul_function_call function: (yul_identifier) @function) + +; Yul function parameters +(yul_function_definition . (yul_identifier) @function (yul_identifier) @variable.parameter) + +(meta_type_expression "type" @keyword) + +(member_expression (property_identifier) @property) +(property_identifier) @property +(struct_expression ((identifier) @property . ":")) +(enum_value) @property + + +; Keywords +[ + "pragma" + "import" + "contract" + "interface" + "library" + "is" + "struct" + "enum" + "event" + "using" + "assembly" + "switch" + "case" + "default" + "break" + "continue" + "if" + "else" + "for" + "while" + "do" + "try" + "catch" + "return" + "emit" + "public" + "internal" + "private" + "external" + "pure" + "view" + "payable" + "modifier" + "returns" + "memory" + "storage" + "calldata" + "function" + "var" + (constant) + (virtual) + (override_specifier) + (yul_leave) +] @keyword + +(import_directive "as" @keyword) +(import_directive "from" @keyword) +(event_paramater "indexed" @keyword) + +; Punctuation + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + + +[ + "." + "," +] @punctuation.delimiter + + +; Operators + +[ + "&&" + "||" + ">>" + ">>>" + "<<" + "&" + "^" + "|" + "+" + "-" + "*" + "/" + "%" + "**" + "<" + "<=" + "==" + "!=" + "!==" + ">=" + ">" + "!" + "~" + "-" + "+" + "delete" + "new" + "++" + "--" +] @operator + +(identifier) @variable +(yul_identifier) @variable + diff --git a/tests/query/highlights/solidity/test.sol b/tests/query/highlights/solidity/test.sol new file mode 100644 index 000000000..8781b60ed --- /dev/null +++ b/tests/query/highlights/solidity/test.sol @@ -0,0 +1,173 @@ +// Example contract from official documentation at https://github.com/ethereum/solidity/blob/v0.8.12/docs/examples/voting.rst + +// SPDX-License-Identifier: GPL-3.0 +// ^ comment +pragma solidity >=0.7.0 <0.9.0; +// ^ keyword +// ^ tag +/// @title Voting with delegation. +// ^ attribute +contract Ballot { +// ^keyword +// ^ type + // This declares a new complex type which will + // be used for variables later. + // It will represent a single voter. + struct Voter { +// ^ type + uint weight; // weight is accumulated by delegation +// ^ type +// ^ variable + bool voted; // if true, that person already voted + address delegate; // person delegated to + uint vote; // index of the voted proposal + } + + // This is a type for a single proposal. + struct Proposal { + bytes32 name; // short name (up to 32 bytes) + uint voteCount; // number of accumulated votes + } + + address public chairperson; +// ^ type + + // This declares a state variable that + // stores a `Voter` struct for each possible address. + mapping(address => Voter) public voters; +// ^ ^ punctuation.bracket +// ^ punctuation.delimiter + + // A dynamically-sized array of `Proposal` structs. + Proposal[] public proposals; + + /// Create a new ballot to choose one of `proposalNames`. + constructor(bytes32[] memory proposalNames) { +// ^ constructor + chairperson = msg.sender; + voters[chairperson].weight = 1; + + // For each of the provided proposal names, + // create a new proposal object and add it + // to the end of the array. + for (uint i = 0; i < proposalNames.length; i++) { + // `Proposal({...})` creates a temporary + // Proposal object and `proposals.push(...)` + // appends it to the end of `proposals`. + proposals.push(Proposal({ + name: proposalNames[i], +// ^ field + voteCount: 0 + })); + } + } + + // Give `voter` the right to vote on this ballot. + // May only be called by `chairperson`. + function giveRightToVote(address voter) external { +// ^ keyword +// ^ function + // If the first argument of `require` evaluates + // to `false`, execution terminates and all + // changes to the state and to Ether balances + // are reverted. + // This used to consume all gas in old EVM versions, but + // not anymore. + // It is often a good idea to use `require` to check if + // functions are called correctly. + // As a second argument, you can also provide an + // explanation about what went wrong. + require( + msg.sender == chairperson, + "Only chairperson can give right to vote." + ); + require( + !voters[voter].voted, + "The voter already voted." + ); + require(voters[voter].weight == 0); + voters[voter].weight = 1; + } + + /// Delegate your vote to the voter `to`. + function delegate(address to) external { + // assigns reference + Voter storage sender = voters[msg.sender]; + require(!sender.voted, "You already voted."); + + require(to != msg.sender, "Self-delegation is disallowed."); + + // Forward the delegation as long as + // `to` also delegated. + // In general, such loops are very dangerous, + // because if they run too long, they might + // need more gas than is available in a block. + // In this case, the delegation will not be executed, + // but in other situations, such loops might + // cause a contract to get "stuck" completely. + while (voters[to].delegate != address(0)) { + to = voters[to].delegate; + + // We found a loop in the delegation, not allowed. + require(to != msg.sender, "Found loop in delegation."); + } + + // Since `sender` is a reference, this + // modifies `voters[msg.sender].voted` + Voter storage delegate_ = voters[to]; + + // Voters cannot delegate to wallets that cannot vote. + require(delegate_.weight >= 1); + sender.voted = true; + sender.delegate = to; + if (delegate_.voted) { + // If the delegate already voted, + // directly add to the number of votes + proposals[delegate_.vote].voteCount += sender.weight; + } else { + // If the delegate did not vote yet, + // add to her weight. + delegate_.weight += sender.weight; + } + } + + /// Give your vote (including votes delegated to you) + /// to proposal `proposals[proposal].name`. + function vote(uint proposal) external { + Voter storage sender = voters[msg.sender]; + require(sender.weight != 0, "Has no right to vote"); + require(!sender.voted, "Already voted."); + sender.voted = true; + sender.vote = proposal; + + // If `proposal` is out of the range of the array, + // this will throw automatically and revert all + // changes. + proposals[proposal].voteCount += sender.weight; + } + + /// @dev Computes the winning proposal taking all + /// previous votes into account. + function winningProposal() public view + returns (uint winningProposal_) + { + uint winningVoteCount = 0; + for (uint p = 0; p < proposals.length; p++) { + if (proposals[p].voteCount > winningVoteCount) { + winningVoteCount = proposals[p].voteCount; + winningProposal_ = p; + } + } + } + + // Calls winningProposal() function to get the index + // of the winner contained in the proposals array and then + // returns the name of the winner + function winnerName() external view + returns (bytes32 winnerName_) + { + winnerName_ = proposals[winningProposal()].name; + } +} + +// vim:ft=solidity |
