mirror of
https://github.com/nvim-treesitter/nvim-treesitter.git
synced 2026-07-19 11:50:09 -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" },
|
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 = {
|
local M = {
|
||||||
list = list,
|
list = list,
|
||||||
filetype_to_parsername = filetype_to_parsername,
|
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