Add highlights query for Solidity

This commit is contained in:
YongJieYongJie 2022-03-10 19:14:49 +08:00 committed by Stephan Seitz
parent 90785a2f1c
commit a180859eea
3 changed files with 375 additions and 0 deletions

View file

@ -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,

View 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

View 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