diff --git a/CHANGES b/CHANGES index 5aa72f037f..b12d578cb0 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,7 @@ Version 2.5.0 * Zeek (new name for Bro) (PR#1264) * Notmuch (PR#1269) * Scdoc (PR#1268) + * Solidity - Updated lexers: diff --git a/pygments/lexers/_mapping.py b/pygments/lexers/_mapping.py index c6fc606c79..acb71ad94b 100644 --- a/pygments/lexers/_mapping.py +++ b/pygments/lexers/_mapping.py @@ -405,6 +405,7 @@ 'SmartyLexer': ('pygments.lexers.templates', 'Smarty', ('smarty',), ('*.tpl',), ('application/x-smarty',)), 'SnobolLexer': ('pygments.lexers.snobol', 'Snobol', ('snobol',), ('*.snobol',), ('text/x-snobol',)), 'SnowballLexer': ('pygments.lexers.dsls', 'Snowball', ('snowball',), ('*.sbl',), ()), + 'SolidityLexer': ('pygments.lexers.solidity', 'Solidity', ('solidity',), ('*.sol',), ()), 'SourcePawnLexer': ('pygments.lexers.pawn', 'SourcePawn', ('sp',), ('*.sp',), ('text/x-sourcepawn',)), 'SourcesListLexer': ('pygments.lexers.installers', 'Debian Sourcelist', ('sourceslist', 'sources.list', 'debsources'), ('sources.list',), ()), 'SparqlLexer': ('pygments.lexers.rdf', 'SPARQL', ('sparql',), ('*.rq', '*.sparql'), ('application/sparql-query',)), diff --git a/pygments/lexers/solidity.py b/pygments/lexers/solidity.py new file mode 100644 index 0000000000..9966837197 --- /dev/null +++ b/pygments/lexers/solidity.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +""" + pygments.lexers.solidity + ~~~~~~~~~~~~~~~~~~~~~~~~ + + Lexers for Solidity. + + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import re + +from pygments.lexer import RegexLexer, bygroups, include, words +from pygments.token import Text, Comment, Operator, Keyword, Name, String, \ + Number, Punctuation + +__all__ = ['SolidityLexer'] + + +class SolidityLexer(RegexLexer): + """ + For Solidity source code. + + .. versionadded:: 2.5 + """ + + name = 'Solidity' + aliases = ['solidity'] + filenames = ['*.sol'] + mimetypes = [] + + flags = re.MULTILINE | re.UNICODE + + datatype = ( + r'\b(address|bool|((bytes|hash|int|string|uint)(8|16|24|32|40|48|56|64' + r'|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208' + r'|216|224|232|240|248|256)?))\b' + ) + + tokens = { + 'root': [ + include('whitespace'), + include('comments'), + (r'\bpragma\s+solidity\b', Keyword, 'pragma'), + (r'\b(contract)(\s+)([a-zA-Z_]\w*)', + bygroups(Keyword, Text.WhiteSpace, Name.Entity)), + (datatype + r'(\s+)((external|public|internal|private)\s+)?' + + r'([a-zA-Z_]\w*)', + bygroups(Keyword.Type, None, None, None, Text.WhiteSpace, Keyword, + None, Name.Variable)), + (r'\b(enum|event|function|struct)(\s+)([a-zA-Z_]\w*)', + bygroups(Keyword.Type, Text.WhiteSpace, Name.Variable)), + (r'\b(msg|block|tx)\.([A-Za-z_][A-Za-z0-9_]*)\b', Keyword), + (words(( + 'block', 'break', 'constant', 'constructor', 'continue', + 'contract', 'do', 'else', 'external', 'false', 'for', + 'function', 'if', 'import', 'inherited', 'internal', 'is', + 'library', 'mapping', 'memory', 'modifier', 'msg', 'new', + 'payable', 'private', 'public', 'require', 'return', + 'returns', 'struct', 'suicide', 'throw', 'this', 'true', + 'tx', 'var', 'while'), prefix=r'\b', suffix=r'\b'), + Keyword.Type), + (words(('keccak256',), prefix=r'\b', suffix=r'\b'), Name.Builtin), + (datatype, Keyword.Type), + include('constants'), + (r'[a-zA-Z_]\w*', Text), + (r'[!<=>+*/-]', Operator), + (r'[.;:{}(),\[\]]', Punctuation) + ], + 'comments': [ + (r'//(\n|[\w\W]*?[^\\]\n)', Comment.Single), + (r'/(\\\n)?[*][\w\W]*?[*](\\\n)?/', Comment.Multiline), + (r'/(\\\n)?[*][\w\W]*', Comment.Multiline) + ], + 'constants': [ + (r'("([\\]"|.)*?")', String.Double), + (r"('([\\]'|.)*?')", String.Single), + (r'\b0[xX][0-9a-fA-F]+\b', Number.Hex), + (r'\b\d+\b', Number.Decimal), + ], + 'pragma': [ + include('whitespace'), + include('comments'), + (r'(\^|>=|<)(\s*)(\d+\.\d+\.\d+)', + bygroups(Operator, Text.WhiteSpace, Keyword)), + (r';', Punctuation, '#pop') + ], + 'whitespace': [ + (r'\s+', Text.WhiteSpace), + (r'\n', Text.WhiteSpace) + ] + } diff --git a/tests/examplefiles/test.sol b/tests/examplefiles/test.sol new file mode 100644 index 0000000000..f7a6495ecb --- /dev/null +++ b/tests/examplefiles/test.sol @@ -0,0 +1,74 @@ +pragma solidity ^0.4.20; + +pragma solidity >=0.4.0 <0.7.0; + +// one-line singleline comment + +/* one-line multiline comment */ + +/* + multi-line multiline comment +*/ + +contract ContractName { + + address public publicaddress; + + uint varname1 = 1234; + int varname2 = 0x12abcdEF; + + string astringsingle = 'test "string" value\' single'; + string astringdouble = "test 'string' value\" double"; + + enum State { + NotStarted, + WorkInProgress, + Done + } + State public state; + + struct AStruct { + string name; + uint8 type; + } + + mapping(address => AStruct) registry; + + event Paid(uint256 value); + event Received(uint256 time); + event Withdraw(uint256 value); + + function addRegistry(string _name, uint8 _type) { + AStruct memory newItem = AStruct({ + name: _name, + type: _type + }); + + registry[msg.sender] = newItem; + } + + function getHash(AStruct item) returns(uint) { + return uint(keccak256(item.name, item.type)); + } + + function pay() public payable { + require(msg.sender == astronaut); + state = State.Paid; + Paid(msg.value); + } + + function receive() public { + require(msg.sender == arbiter); + require(state == State.Paid); + state = State.Received; + Received(now); + } + + function withdraw() public { + require(msg.sender == shipper); + require(state == State.Received); + state = State.Withdrawn; + Withdraw(this.balance); + shipper.transfer(this.balance); + } +}