mirror of
https://github.com/nvim-treesitter/nvim-treesitter.git
synced 2026-07-01 19:17:02 -04:00
Add highlights query for Solidity
This commit is contained in:
parent
90785a2f1c
commit
a180859eea
3 changed files with 375 additions and 0 deletions
|
|
@ -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,
|
||||
|
|
|
|||
193
queries/solidity/highlights.scm
Normal file
193
queries/solidity/highlights.scm
Normal file
|
|
@ -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
|
||||
|
||||
173
tests/query/highlights/solidity/test.sol
Normal file
173
tests/query/highlights/solidity/test.sol
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue