summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Hatch <tim@timhatch.com>2016-05-31 17:07:04 -0700
committerTim Hatch <tim@timhatch.com>2016-05-31 17:07:04 -0700
commit9be7169467e3ab7b3e1fa9b3e4b310786e6a6366 (patch)
tree3e6718b8f0dc4803b65ad0443dd13d027d4f616c
parent91a745b350964b1815668bca9f48564cbb80a7ea (diff)
parentd71746908e0b92daec6a7504121b4de939b9c9e5 (diff)
downloadpygments-git-9be7169467e3ab7b3e1fa9b3e4b310786e6a6366.tar.gz
Merged in MostAwesomeDude/pygments-main (pull request #592)
-rw-r--r--AUTHORS9
-rw-r--r--doc/languages.rst1
-rwxr-xr-xexternal/autopygmentize1
-rw-r--r--pygments/lexers/_lua_builtins.py92
-rw-r--r--pygments/lexers/_mapping.py13
-rw-r--r--pygments/lexers/_tsql_builtins.py1004
-rw-r--r--pygments/lexers/asm.py83
-rw-r--r--pygments/lexers/bibtex.py156
-rw-r--r--pygments/lexers/compiled.py1
-rw-r--r--pygments/lexers/crystal.py384
-rw-r--r--pygments/lexers/dsls.py115
-rw-r--r--pygments/lexers/esoteric.py98
-rw-r--r--pygments/lexers/javascript.py62
-rw-r--r--pygments/lexers/make.py2
-rw-r--r--pygments/lexers/other.py1
-rw-r--r--pygments/lexers/rust.py41
-rw-r--r--pygments/lexers/scripting.py62
-rw-r--r--pygments/lexers/shell.py4
-rw-r--r--pygments/lexers/smv.py75
-rw-r--r--pygments/lexers/sql.py68
-rw-r--r--pygments/lexers/templates.py78
-rw-r--r--pygments/lexers/verification.py7
-rw-r--r--pygments/lexers/whiley.py117
-rw-r--r--tests/examplefiles/capdl_example.cdl64
-rw-r--r--tests/examplefiles/durexmania.aheui4
-rw-r--r--tests/examplefiles/example.bat2
-rw-r--r--tests/examplefiles/example.juttle110
-rw-r--r--tests/examplefiles/example.lua24
-rw-r--r--tests/examplefiles/example.ng211
-rw-r--r--tests/examplefiles/example.sbl109
-rw-r--r--tests/examplefiles/example.tasm527
-rw-r--r--tests/examplefiles/example.whiley296
-rw-r--r--tests/examplefiles/fibonacci.tokigun.aheui4
-rw-r--r--tests/examplefiles/guidance.smv1124
-rw-r--r--tests/examplefiles/hello-world.puzzlet.aheui10
-rw-r--r--tests/examplefiles/plain.bst1097
-rw-r--r--tests/examplefiles/test.bib77
-rw-r--r--tests/examplefiles/test.cr2871
-rw-r--r--tests/examplefiles/tsql_example.sql72
-rw-r--r--tests/test_bibtex.py236
-rw-r--r--tests/test_crystal.py308
-rw-r--r--tests/test_sql.py74
-rw-r--r--tests/test_whiley.py30
43 files changed, 9445 insertions, 79 deletions
diff --git a/AUTHORS b/AUTHORS
index e4084203..42650444 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -7,7 +7,7 @@ Other contributors, listed alphabetically, are:
* Sam Aaron -- Ioke lexer
* Ali Afshar -- image formatter
-* Thomas Aglassinger -- Easytrieve, JCL and Rexx lexers
+* Thomas Aglassinger -- Easytrieve, JCL, Rexx and Transact-SQL lexers
* Muthiah Annamalai -- Ezhil lexer
* Kumar Appaiah -- Debian control lexer
* Andreas Amann -- AppleScript lexer
@@ -37,7 +37,7 @@ Other contributors, listed alphabetically, are:
* chebee7i -- Python traceback lexer improvements
* Hiram Chirino -- Scaml and Jade lexers
* Ian Cooper -- VGL lexer
-* David Corbett -- Inform, Jasmin, JSGF, and TADS 3 lexers
+* David Corbett -- Inform, Jasmin, JSGF, Snowball, and TADS 3 lexers
* Leaf Corcoran -- MoonScript lexer
* Christopher Creutzig -- MuPAD lexer
* Daniël W. Crompton -- Pike lexer
@@ -65,6 +65,7 @@ Other contributors, listed alphabetically, are:
* Alex Gilding -- BlitzBasic lexer
* Bertrand Goetzmann -- Groovy lexer
* Krzysiek Goj -- Scala lexer
+* Andrey Golovizin -- BibTeX lexers
* Matt Good -- Genshi, Cheetah lexers
* Michał Górny -- vim modeline support
* Alex Gosse -- TrafficScript lexer
@@ -152,6 +153,7 @@ Other contributors, listed alphabetically, are:
* Dominik Picheta -- Nimrod lexer
* Andrew Pinkham -- RTF Formatter Refactoring
* Clément Prévost -- UrbiScript lexer
+* Oleh Prypin -- Crystal lexer (based on Ruby lexer)
* Elias Rabel -- Fortran fixed form lexer
* raichoo -- Idris lexer
* Kashif Rasul -- CUDA lexer
@@ -169,6 +171,7 @@ Other contributors, listed alphabetically, are:
* Matteo Sasso -- Common Lisp lexer
* Joe Schafer -- Ada lexer
* Ken Schutte -- Matlab lexers
+* Sebastian Schweizer -- Whiley lexer
* Tassilo Schweyer -- Io, MOOCode lexers
* Ted Shaw -- AutoIt lexer
* Joerg Sieker -- ABAP lexer
@@ -178,7 +181,7 @@ Other contributors, listed alphabetically, are:
* Alexander Smishlajev -- Visual FoxPro lexer
* Steve Spigarelli -- XQuery lexer
* Jerome St-Louis -- eC lexer
-* Camil Staps -- Clean lexer
+* Camil Staps -- Clean and NuSMV lexers
* James Strachan -- Kotlin lexer
* Tom Stuart -- Treetop lexer
* Colin Sullivan -- SuperCollider lexer
diff --git a/doc/languages.rst b/doc/languages.rst
index ffe1bdb6..7fa8eb2f 100644
--- a/doc/languages.rst
+++ b/doc/languages.rst
@@ -26,6 +26,7 @@ Programming languages
* Common Lisp
* Coq
* Cryptol (incl. Literate Cryptol)
+* `Crystal <http://crystal-lang.org>`_
* `Cython <http://cython.org>`_
* `D <http://dlang.org>`_
* Dart
diff --git a/external/autopygmentize b/external/autopygmentize
index 7873c22a..f18cac09 100755
--- a/external/autopygmentize
+++ b/external/autopygmentize
@@ -40,6 +40,7 @@ if [[ "$lexer" == text ]]; then
text/x-po) lexer=po;;
text/x-python) lexer=python;;
text/x-ruby) lexer=ruby;;
+ text/x-crystal) lexer=crystal;;
text/x-shellscript) lexer=sh;;
text/x-tcl) lexer=tcl;;
text/x-tex|text/x-texinfo) lexer=latex;; # FIXME: texinfo really needs its own lexer
diff --git a/pygments/lexers/_lua_builtins.py b/pygments/lexers/_lua_builtins.py
index 6d2929b6..7472b9e6 100644
--- a/pygments/lexers/_lua_builtins.py
+++ b/pygments/lexers/_lua_builtins.py
@@ -15,54 +15,65 @@
from __future__ import print_function
-
MODULES = {'basic': ('_G',
'_VERSION',
'assert',
'collectgarbage',
'dofile',
'error',
- 'getfenv',
'getmetatable',
'ipairs',
'load',
'loadfile',
- 'loadstring',
'next',
'pairs',
'pcall',
'print',
'rawequal',
'rawget',
+ 'rawlen',
'rawset',
'select',
- 'setfenv',
'setmetatable',
'tonumber',
'tostring',
'type',
- 'unpack',
'xpcall'),
+ 'bit32': ('bit32.arshift',
+ 'bit32.band',
+ 'bit32.bnot',
+ 'bit32.bor',
+ 'bit32.btest',
+ 'bit32.bxor',
+ 'bit32.extract',
+ 'bit32.lrotate',
+ 'bit32.lshift',
+ 'bit32.replace',
+ 'bit32.rrotate',
+ 'bit32.rshift'),
'coroutine': ('coroutine.create',
+ 'coroutine.isyieldable',
'coroutine.resume',
'coroutine.running',
'coroutine.status',
'coroutine.wrap',
'coroutine.yield'),
'debug': ('debug.debug',
- 'debug.getfenv',
'debug.gethook',
'debug.getinfo',
'debug.getlocal',
'debug.getmetatable',
'debug.getregistry',
'debug.getupvalue',
- 'debug.setfenv',
+ 'debug.getuservalue',
'debug.sethook',
'debug.setlocal',
'debug.setmetatable',
'debug.setupvalue',
- 'debug.traceback'),
+ 'debug.setuservalue',
+ 'debug.traceback',
+ 'debug.upvalueid',
+ 'debug.upvaluejoin'),
'io': ('io.close',
'io.flush',
'io.input',
@@ -71,17 +82,20 @@ MODULES = {'basic': ('_G',
'io.output',
'io.popen',
'io.read',
+ 'io.stderr',
+ 'io.stdin',
+ 'io.stdout',
'io.tmpfile',
'io.type',
'io.write'),
'math': ('math.abs',
'math.acos',
'math.asin',
- 'math.atan2',
'math.atan',
+ 'math.atan2',
'math.ceil',
- 'math.cosh',
'math.cos',
+ 'math.cosh',
'math.deg',
'math.exp',
'math.floor',
@@ -89,29 +103,34 @@ MODULES = {'basic': ('_G',
'math.frexp',
'math.huge',
'math.ldexp',
- 'math.log10',
'math.log',
'math.max',
+ 'math.maxinteger',
'math.min',
+ 'math.mininteger',
'math.modf',
'math.pi',
'math.pow',
'math.rad',
'math.random',
'math.randomseed',
- 'math.sinh',
'math.sin',
+ 'math.sinh',
'math.sqrt',
+ 'math.tan',
'math.tanh',
- 'math.tan'),
- 'modules': ('module',
- 'require',
+ 'math.tointeger',
+ 'math.type',
+ 'math.ult'),
+ 'modules': ('package.config',
'package.cpath',
'package.loaded',
'package.loadlib',
'package.path',
'package.preload',
- 'package.seeall'),
+ 'package.searchers',
+ 'package.searchpath',
+ 'require'),
'os': ('os.clock',
'os.date',
'os.difftime',
@@ -133,19 +152,37 @@ MODULES = {'basic': ('_G',
'string.len',
'string.lower',
'string.match',
+ 'string.pack',
+ 'string.packsize',
'string.rep',
'string.reverse',
'string.sub',
+ 'string.unpack',
'string.upper'),
'table': ('table.concat',
'table.insert',
- 'table.maxn',
+ 'table.move',
+ 'table.pack',
'table.remove',
- 'table.sort')}
-
+ 'table.sort',
+ 'table.unpack'),
+ 'utf8': ('utf8.char',
+ 'utf8.charpattern',
+ 'utf8.codepoint',
+ 'utf8.codes',
+ 'utf8.len',
+ 'utf8.offset')}
if __name__ == '__main__': # pragma: no cover
import re
+ import sys
+
+ # urllib ends up wanting to import a module called 'math' -- if
+ # pygments/lexers is in the path, this ends badly.
+ for i in range(len(sys.path)-1, -1, -1):
+ if sys.path[i].endswith('/lexers'):
+ del sys.path[i]
+
try:
from urllib import urlopen
except ImportError:
@@ -196,7 +233,7 @@ if __name__ == '__main__': # pragma: no cover
def get_newest_version():
f = urlopen('http://www.lua.org/manual/')
- r = re.compile(r'^<A HREF="(\d\.\d)/">Lua \1</A>')
+ r = re.compile(r'^<A HREF="(\d\.\d)/">(Lua )?\1</A>')
for line in f:
m = r.match(line)
if m is not None:
@@ -204,7 +241,7 @@ if __name__ == '__main__': # pragma: no cover
def get_lua_functions(version):
f = urlopen('http://www.lua.org/manual/%s/' % version)
- r = re.compile(r'^<A HREF="manual.html#pdf-(.+)">\1</A>')
+ r = re.compile(r'^<A HREF="manual.html#pdf-(?!lua|LUA)([^:]+)">\1</A>')
functions = []
for line in f:
m = r.match(line)
@@ -236,15 +273,22 @@ if __name__ == '__main__': # pragma: no cover
def run():
version = get_newest_version()
- print('> Downloading function index for Lua %s' % version)
- functions = get_lua_functions(version)
- print('> %d functions found:' % len(functions))
+ functions = set()
+ for v in ('5.2', version):
+ print('> Downloading function index for Lua %s' % v)
+ f = get_lua_functions(v)
+ print('> %d functions found, %d new:' %
+ (len(f), len(set(f) - functions)))
+ functions |= set(f)
+
+ functions = sorted(functions)
modules = {}
for full_function_name in functions:
print('>> %s' % full_function_name)
m = get_function_module(full_function_name)
modules.setdefault(m, []).append(full_function_name)
+ modules = {k: tuple(v) for k, v in modules.iteritems()}
regenerate(__file__, modules)
diff --git a/pygments/lexers/_mapping.py b/pygments/lexers/_mapping.py
index e7ee7b2e..9889d2b6 100644
--- a/pygments/lexers/_mapping.py
+++ b/pygments/lexers/_mapping.py
@@ -24,9 +24,12 @@ LEXERS = {
'AdaLexer': ('pygments.lexers.pascal', 'Ada', ('ada', 'ada95', 'ada2005'), ('*.adb', '*.ads', '*.ada'), ('text/x-ada',)),
'AdlLexer': ('pygments.lexers.archetype', 'ADL', ('adl',), ('*.adl', '*.adls', '*.adlf', '*.adlx'), ()),
'AgdaLexer': ('pygments.lexers.haskell', 'Agda', ('agda',), ('*.agda',), ('text/x-agda',)),
+ 'AheuiLexer': ('pygments.lexers.esoteric', 'Aheui', ('aheui',), ('*.aheui',), ()),
'AlloyLexer': ('pygments.lexers.dsls', 'Alloy', ('alloy',), ('*.als',), ('text/x-alloy',)),
'AmbientTalkLexer': ('pygments.lexers.ambient', 'AmbientTalk', ('at', 'ambienttalk', 'ambienttalk/2'), ('*.at',), ('text/x-ambienttalk',)),
'AmplLexer': ('pygments.lexers.ampl', 'Ampl', ('ampl',), ('*.run',), ()),
+ 'Angular2HtmlLexer': ('pygments.lexers.templates', 'HTML + Angular2', ('html+ng2',), ('*.ng2',), ()),
+ 'Angular2Lexer': ('pygments.lexers.templates', 'Angular2', ('ng2',), (), ()),
'AntlrActionScriptLexer': ('pygments.lexers.parsers', 'ANTLR With ActionScript Target', ('antlr-as', 'antlr-actionscript'), ('*.G', '*.g'), ()),
'AntlrCSharpLexer': ('pygments.lexers.parsers', 'ANTLR With C# Target', ('antlr-csharp', 'antlr-c#'), ('*.G', '*.g'), ()),
'AntlrCppLexer': ('pygments.lexers.parsers', 'ANTLR With CPP Target', ('antlr-cpp',), ('*.G', '*.g'), ()),
@@ -46,11 +49,13 @@ LEXERS = {
'AwkLexer': ('pygments.lexers.textedit', 'Awk', ('awk', 'gawk', 'mawk', 'nawk'), ('*.awk',), ('application/x-awk',)),
'BBCodeLexer': ('pygments.lexers.markup', 'BBCode', ('bbcode',), (), ('text/x-bbcode',)),
'BCLexer': ('pygments.lexers.algebra', 'BC', ('bc',), ('*.bc',), ()),
+ 'BSTLexer': ('pygments.lexers.bibtex', 'BST', ('bst', 'bst-pybtex'), ('*.bst',), ()),
'BaseMakefileLexer': ('pygments.lexers.make', 'Base Makefile', ('basemake',), (), ()),
'BashLexer': ('pygments.lexers.shell', 'Bash', ('bash', 'sh', 'ksh', 'shell'), ('*.sh', '*.ksh', '*.bash', '*.ebuild', '*.eclass', '*.exheres-0', '*.exlib', '.bashrc', 'bashrc', '.bash_*', 'bash_*', 'PKGBUILD'), ('application/x-sh', 'application/x-shellscript')),
'BashSessionLexer': ('pygments.lexers.shell', 'Bash Session', ('console', 'shell-session'), ('*.sh-session', '*.shell-session'), ('application/x-shell-session', 'application/x-sh-session')),
'BatchLexer': ('pygments.lexers.shell', 'Batchfile', ('bat', 'batch', 'dosbatch', 'winbatch'), ('*.bat', '*.cmd'), ('application/x-dos-batch',)),
'BefungeLexer': ('pygments.lexers.esoteric', 'Befunge', ('befunge',), ('*.befunge',), ('application/x-befunge',)),
+ 'BibTeXLexer': ('pygments.lexers.bibtex', 'BibTeX', ('bib', 'bibtex'), ('*.bib',), ('text/x-bibtex',)),
'BlitzBasicLexer': ('pygments.lexers.basic', 'BlitzBasic', ('blitzbasic', 'b3d', 'bplus'), ('*.bb', '*.decls'), ('text/x-bb',)),
'BlitzMaxLexer': ('pygments.lexers.basic', 'BlitzMax', ('blitzmax', 'bmax'), ('*.bmx',), ('text/x-bmx',)),
'BnfLexer': ('pygments.lexers.grammar_notation', 'BNF', ('bnf',), ('*.bnf',), ('text/x-bnf',)),
@@ -68,6 +73,7 @@ LEXERS = {
'CSharpLexer': ('pygments.lexers.dotnet', 'C#', ('csharp', 'c#'), ('*.cs',), ('text/x-csharp',)),
'Ca65Lexer': ('pygments.lexers.asm', 'ca65 assembler', ('ca65',), ('*.s',), ()),
'CadlLexer': ('pygments.lexers.archetype', 'cADL', ('cadl',), ('*.cadl',), ()),
+ 'CapDLLexer': ('pygments.lexers.esoteric', 'CapDL', ('capdl',), ('*.cdl',), ()),
'CbmBasicV2Lexer': ('pygments.lexers.basic', 'CBM BASIC V2', ('cbmbas',), ('*.bas',), ()),
'CeylonLexer': ('pygments.lexers.jvm', 'Ceylon', ('ceylon',), ('*.ceylon',), ('text/x-ceylon',)),
'Cfengine3Lexer': ('pygments.lexers.configs', 'CFEngine3', ('cfengine3', 'cf3'), ('*.cf',), ()),
@@ -96,6 +102,7 @@ LEXERS = {
'CrmshLexer': ('pygments.lexers.dsls', 'Crmsh', ('crmsh', 'pcmk'), ('*.crmsh', '*.pcmk'), ()),
'CrocLexer': ('pygments.lexers.d', 'Croc', ('croc',), ('*.croc',), ('text/x-crocsrc',)),
'CryptolLexer': ('pygments.lexers.haskell', 'Cryptol', ('cryptol', 'cry'), ('*.cry',), ('text/x-cryptol',)),
+ 'CrystalLexer': ('pygments.lexers.crystal', 'Crystal', ('cr', 'crystal'), ('*.cr',), ('text/x-crystal',)),
'CsoundDocumentLexer': ('pygments.lexers.csound', 'Csound Document', ('csound-document', 'csound-csd'), ('*.csd',), ()),
'CsoundOrchestraLexer': ('pygments.lexers.csound', 'Csound Orchestra', ('csound', 'csound-orc'), ('*.orc',), ()),
'CsoundScoreLexer': ('pygments.lexers.csound', 'Csound Score', ('csound-score', 'csound-sco'), ('*.sco',), ()),
@@ -210,6 +217,7 @@ LEXERS = {
'JspLexer': ('pygments.lexers.templates', 'Java Server Page', ('jsp',), ('*.jsp',), ('application/x-jsp',)),
'JuliaConsoleLexer': ('pygments.lexers.julia', 'Julia console', ('jlcon',), (), ()),
'JuliaLexer': ('pygments.lexers.julia', 'Julia', ('julia', 'jl'), ('*.jl',), ('text/x-julia', 'application/x-julia')),
+ 'JuttleLexer': ('pygments.lexers.javascript', 'Juttle', ('juttle', 'juttle'), ('*.juttle',), ('application/juttle', 'application/x-juttle', 'text/x-juttle', 'text/juttle')),
'KalLexer': ('pygments.lexers.javascript', 'Kal', ('kal',), ('*.kal',), ('text/kal', 'application/kal')),
'KconfigLexer': ('pygments.lexers.configs', 'Kconfig', ('kconfig', 'menuconfig', 'linux-config', 'kernel-config'), ('Kconfig', '*Config.in*', 'external.in*', 'standard-modules.in'), ('text/x-kconfig',)),
'KokaLexer': ('pygments.lexers.haskell', 'Koka', ('koka',), ('*.kk', '*.kki'), ('text/x-koka',)),
@@ -282,6 +290,7 @@ LEXERS = {
'NimrodLexer': ('pygments.lexers.nimrod', 'Nimrod', ('nim', 'nimrod'), ('*.nim', '*.nimrod'), ('text/x-nim',)),
'NitLexer': ('pygments.lexers.nit', 'Nit', ('nit',), ('*.nit',), ()),
'NixLexer': ('pygments.lexers.nix', 'Nix', ('nixos', 'nix'), ('*.nix',), ('text/x-nix',)),
+ 'NuSMVLexer': ('pygments.lexers.smv', 'NuSMV', ('nusmv',), ('*.smv',), ()),
'NumPyLexer': ('pygments.lexers.python', 'NumPy', ('numpy',), (), ()),
'ObjdumpLexer': ('pygments.lexers.asm', 'objdump', ('objdump',), ('*.objdump',), ('text/x-objdump',)),
'ObjectiveCLexer': ('pygments.lexers.objective', 'Objective-C', ('objective-c', 'objectivec', 'obj-c', 'objc'), ('*.m', '*.h'), ('text/x-objective-c',)),
@@ -369,6 +378,7 @@ LEXERS = {
'SmalltalkLexer': ('pygments.lexers.smalltalk', 'Smalltalk', ('smalltalk', 'squeak', 'st'), ('*.st',), ('text/x-smalltalk',)),
'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',), ()),
'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',)),
@@ -383,6 +393,7 @@ LEXERS = {
'SystemVerilogLexer': ('pygments.lexers.hdl', 'systemverilog', ('systemverilog', 'sv'), ('*.sv', '*.svh'), ('text/x-systemverilog',)),
'TAPLexer': ('pygments.lexers.testing', 'TAP', ('tap',), ('*.tap',), ()),
'Tads3Lexer': ('pygments.lexers.int_fiction', 'TADS 3', ('tads3',), ('*.t',), ()),
+ 'TasmLexer': ('pygments.lexers.asm', 'TASM', ('tasm',), ('*.asm', '*.ASM', '*.tasm'), ('text/x-tasm',)),
'TclLexer': ('pygments.lexers.tcl', 'Tcl', ('tcl',), ('*.tcl', '*.rvt'), ('text/x-tcl', 'text/x-script.tcl', 'application/x-tcl')),
'TcshLexer': ('pygments.lexers.shell', 'Tcsh', ('tcsh', 'csh'), ('*.tcsh', '*.csh'), ('application/x-csh',)),
'TcshSessionLexer': ('pygments.lexers.shell', 'Tcsh Session', ('tcshcon',), (), ()),
@@ -394,6 +405,7 @@ LEXERS = {
'TextLexer': ('pygments.lexers.special', 'Text only', ('text',), ('*.txt',), ('text/plain',)),
'ThriftLexer': ('pygments.lexers.dsls', 'Thrift', ('thrift',), ('*.thrift',), ('application/x-thrift',)),
'TodotxtLexer': ('pygments.lexers.textfmts', 'Todotxt', ('todotxt',), ('todo.txt', '*.todotxt'), ('text/x-todo',)),
+ 'TransactSqlLexer': ('pygments.lexers.sql', 'Transact-SQL', ('tsql', 't-sql'), ('*.sql',), ('text/x-tsql',)),
'TreetopLexer': ('pygments.lexers.parsers', 'Treetop', ('treetop',), ('*.treetop', '*.tt'), ()),
'TurtleLexer': ('pygments.lexers.rdf', 'Turtle', ('turtle',), ('*.ttl',), ('text/turtle', 'application/x-turtle')),
'TwigHtmlLexer': ('pygments.lexers.templates', 'HTML+Twig', ('html+twig',), ('*.twig',), ('text/html+twig',)),
@@ -417,6 +429,7 @@ LEXERS = {
'VhdlLexer': ('pygments.lexers.hdl', 'vhdl', ('vhdl',), ('*.vhdl', '*.vhd'), ('text/x-vhdl',)),
'VimLexer': ('pygments.lexers.textedit', 'VimL', ('vim',), ('*.vim', '.vimrc', '.exrc', '.gvimrc', '_vimrc', '_exrc', '_gvimrc', 'vimrc', 'gvimrc'), ('text/x-vim',)),
'WDiffLexer': ('pygments.lexers.diff', 'WDiff', ('wdiff',), ('*.wdiff',), ()),
+ 'WhileyLexer': ('pygments.lexers.whiley', 'Whiley', ('whiley',), ('*.whiley',), ('text/x-whiley',)),
'X10Lexer': ('pygments.lexers.x10', 'X10', ('x10', 'xten'), ('*.x10',), ('text/x-x10',)),
'XQueryLexer': ('pygments.lexers.webmisc', 'XQuery', ('xquery', 'xqy', 'xq', 'xql', 'xqm'), ('*.xqy', '*.xquery', '*.xq', '*.xql', '*.xqm'), ('text/xquery', 'application/xquery')),
'XmlDjangoLexer': ('pygments.lexers.templates', 'XML+Django/Jinja', ('xml+django', 'xml+jinja'), (), ('application/xml+django', 'application/xml+jinja')),
diff --git a/pygments/lexers/_tsql_builtins.py b/pygments/lexers/_tsql_builtins.py
new file mode 100644
index 00000000..44ad8244
--- /dev/null
+++ b/pygments/lexers/_tsql_builtins.py
@@ -0,0 +1,1004 @@
+# -*- coding: utf-8 -*-
+"""
+ pygments.lexers._tsql_builtins
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ These are manually translated lists from https://msdn.microsoft.com.
+
+ :copyright: Copyright 2006-2015 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+# See https://msdn.microsoft.com/en-us/library/ms174986.aspx.
+OPERATORS = (
+ '!<',
+ '!=',
+ '!>',
+ '<',
+ '<=',
+ '<>',
+ '=',
+ '>',
+ '>=',
+ '+',
+ '+=',
+ '-',
+ '-=',
+ '*',
+ '*=',
+ '/',
+ '/=',
+ '%',
+ '%=',
+ '&',
+ '&=',
+ '|',
+ '|=',
+ '^',
+ '^=',
+ '~',
+ '::',
+)
+
+OPERATOR_WORDS = (
+ 'all',
+ 'and',
+ 'any',
+ 'between',
+ 'except',
+ 'exists',
+ 'in',
+ 'intersect',
+ 'like',
+ 'not',
+ 'or',
+ 'some',
+ 'union',
+)
+
+_KEYWORDS_SERVER = (
+ 'add',
+ 'all',
+ 'alter',
+ 'and',
+ 'any',
+ 'as',
+ 'asc',
+ 'authorization',
+ 'backup',
+ 'begin',
+ 'between',
+ 'break',
+ 'browse',
+ 'bulk',
+ 'by',
+ 'cascade',
+ 'case',
+ 'catch',
+ 'check',
+ 'checkpoint',
+ 'close',
+ 'clustered',
+ 'coalesce',
+ 'collate',
+ 'column',
+ 'commit',
+ 'compute',
+ 'constraint',
+ 'contains',
+ 'containstable',
+ 'continue',
+ 'convert',
+ 'create',
+ 'cross',
+ 'current',
+ 'current_date',
+ 'current_time',
+ 'current_timestamp',
+ 'current_user',
+ 'cursor',
+ 'database',
+ 'dbcc',
+ 'deallocate',
+ 'declare',
+ 'default',
+ 'delete',
+ 'deny',
+ 'desc',
+ 'disk',
+ 'distinct',
+ 'distributed',
+ 'double',
+ 'drop',
+ 'dump',
+ 'else',
+ 'end',
+ 'errlvl',
+ 'escape',
+ 'except',
+ 'exec',
+ 'execute',
+ 'exists',
+ 'exit',
+ 'external',
+ 'fetch',
+ 'file',
+ 'fillfactor',
+ 'for',
+ 'foreign',
+ 'freetext',
+ 'freetexttable',
+ 'from',
+ 'full',
+ 'function',
+ 'goto',
+ 'grant',
+ 'group',
+ 'having',
+ 'holdlock',
+ 'identity',
+ 'identity_insert',
+ 'identitycol',
+ 'if',
+ 'in',
+ 'index',
+ 'inner',
+ 'insert',
+ 'intersect',
+ 'into',
+ 'is',
+ 'join',
+ 'key',
+ 'kill',
+ 'left',
+ 'like',
+ 'lineno',
+ 'load',
+ 'merge',
+ 'national',
+ 'nocheck',
+ 'nonclustered',
+ 'not',
+ 'null',
+ 'nullif',
+ 'of',
+ 'off',
+ 'offsets',
+ 'on',
+ 'open',
+ 'opendatasource',
+ 'openquery',
+ 'openrowset',
+ 'openxml',
+ 'option',
+ 'or',
+ 'order',
+ 'outer',
+ 'over',
+ 'percent',
+ 'pivot',
+ 'plan',
+ 'precision',
+ 'primary',
+ 'print',
+ 'proc',
+ 'procedure',
+ 'public',
+ 'raiserror',
+ 'read',
+ 'readtext',
+ 'reconfigure',
+ 'references',
+ 'replication',
+ 'restore',
+ 'restrict',
+ 'return',
+ 'revert',
+ 'revoke',
+ 'right',
+ 'rollback',
+ 'rowcount',
+ 'rowguidcol',
+ 'rule',
+ 'save',
+ 'schema',
+ 'securityaudit',
+ 'select',
+ 'semantickeyphrasetable',
+ 'semanticsimilaritydetailstable',
+ 'semanticsimilaritytable',
+ 'session_user',
+ 'set',
+ 'setuser',
+ 'shutdown',
+ 'some',
+ 'statistics',
+ 'system_user',
+ 'table',
+ 'tablesample',
+ 'textsize',
+ 'then',
+ 'throw',
+ 'to',
+ 'top',
+ 'tran',
+ 'transaction',
+ 'trigger',
+ 'truncate',
+ 'try',
+ 'try_convert',
+ 'tsequal',
+ 'union',
+ 'unique',
+ 'unpivot',
+ 'update',
+ 'updatetext',
+ 'use',
+ 'user',
+ 'values',
+ 'varying',
+ 'view',
+ 'waitfor',
+ 'when',
+ 'where',
+ 'while',
+ 'with',
+ 'within',
+ 'writetext',
+)
+
+_KEYWORDS_FUTURE = (
+ 'absolute',
+ 'action',
+ 'admin',
+ 'after',
+ 'aggregate',
+ 'alias',
+ 'allocate',
+ 'are',
+ 'array',
+ 'asensitive',
+ 'assertion',
+ 'asymmetric',
+ 'at',
+ 'atomic',
+ 'before',
+ 'binary',
+ 'bit',
+ 'blob',
+ 'boolean',
+ 'both',
+ 'breadth',
+ 'call',
+ 'called',
+ 'cardinality',
+ 'cascaded',
+ 'cast',
+ 'catalog',
+ 'char',
+ 'character',
+ 'class',
+ 'clob',
+ 'collation',
+ 'collect',
+ 'completion',
+ 'condition',
+ 'connect',
+ 'connection',
+ 'constraints',
+ 'constructor',
+ 'corr',
+ 'corresponding',
+ 'covar_pop',
+ 'covar_samp',
+ 'cube',
+ 'cume_dist',
+ 'current_catalog',
+ 'current_default_transform_group',
+ 'current_path',
+ 'current_role',
+ 'current_schema',
+ 'current_transform_group_for_type',
+ 'cycle',
+ 'data',
+ 'date',
+ 'day',
+ 'dec',
+ 'decimal',
+ 'deferrable',
+ 'deferred',
+ 'depth',
+ 'deref',
+ 'describe',
+ 'descriptor',
+ 'destroy',
+ 'destructor',
+ 'deterministic',
+ 'diagnostics',
+ 'dictionary',
+ 'disconnect',
+ 'domain',
+ 'dynamic',
+ 'each',
+ 'element',
+ 'end-exec',
+ 'equals',
+ 'every',
+ 'exception',
+ 'false',
+ 'filter',
+ 'first',
+ 'float',
+ 'found',
+ 'free',
+ 'fulltexttable',
+ 'fusion',
+ 'general',
+ 'get',
+ 'global',
+ 'go',
+ 'grouping',
+ 'hold',
+ 'host',
+ 'hour',
+ 'ignore',
+ 'immediate',
+ 'indicator',
+ 'initialize',
+ 'initially',
+ 'inout',
+ 'input',
+ 'int',
+ 'integer',
+ 'intersection',
+ 'interval',
+ 'isolation',
+ 'iterate',
+ 'language',
+ 'large',
+ 'last',
+ 'lateral',
+ 'leading',
+ 'less',
+ 'level',
+ 'like_regex',
+ 'limit',
+ 'ln',
+ 'local',
+ 'localtime',
+ 'localtimestamp',
+ 'locator',
+ 'map',
+ 'match',
+ 'member',
+ 'method',
+ 'minute',
+ 'mod',
+ 'modifies',
+ 'modify',
+ 'module',
+ 'month',
+ 'multiset',
+ 'names',
+ 'natural',
+ 'nchar',
+ 'nclob',
+ 'new',
+ 'next',
+ 'no',
+ 'none',
+ 'normalize',
+ 'numeric',
+ 'object',
+ 'occurrences_regex',
+ 'old',
+ 'only',
+ 'operation',
+ 'ordinality',
+ 'out',
+ 'output',
+ 'overlay',
+ 'pad',
+ 'parameter',
+ 'parameters',
+ 'partial',
+ 'partition',
+ 'path',
+ 'percent_rank',
+ 'percentile_cont',
+ 'percentile_disc',
+ 'position_regex',
+ 'postfix',
+ 'prefix',
+ 'preorder',
+ 'prepare',
+ 'preserve',
+ 'prior',
+ 'privileges',
+ 'range',
+ 'reads',
+ 'real',
+ 'recursive',
+ 'ref',
+ 'referencing',
+ 'regr_avgx',
+ 'regr_avgy',
+ 'regr_count',
+ 'regr_intercept',
+ 'regr_r2',
+ 'regr_slope',
+ 'regr_sxx',
+ 'regr_sxy',
+ 'regr_syy',
+ 'relative',
+ 'release',
+ 'result',
+ 'returns',
+ 'role',
+ 'rollup',
+ 'routine',
+ 'row',
+ 'rows',
+ 'savepoint',
+ 'scope',
+ 'scroll',
+ 'search',
+ 'second',
+ 'section',
+ 'sensitive',
+ 'sequence',
+ 'session',
+ 'sets',
+ 'similar',
+ 'size',
+ 'smallint',
+ 'space',
+ 'specific',
+ 'specifictype',
+ 'sql',
+ 'sqlexception',
+ 'sqlstate',
+ 'sqlwarning',
+ 'start',
+ 'state',
+ 'statement',
+ 'static',
+ 'stddev_pop',
+ 'stddev_samp',
+ 'structure',
+ 'submultiset',
+ 'substring_regex',
+ 'symmetric',
+ 'system',
+ 'temporary',
+ 'terminate',
+ 'than',
+ 'time',
+ 'timestamp',
+ 'timezone_hour',
+ 'timezone_minute',
+ 'trailing',
+ 'translate_regex',
+ 'translation',
+ 'treat',
+ 'true',
+ 'uescape',
+ 'under',
+ 'unknown',
+ 'unnest',
+ 'usage',
+ 'using',
+ 'value',
+ 'var_pop',
+ 'var_samp',
+ 'varchar',
+ 'variable',
+ 'whenever',
+ 'width_bucket',
+ 'window',
+ 'within',
+ 'without',
+ 'work',
+ 'write',
+ 'xmlagg',
+ 'xmlattributes',
+ 'xmlbinary',
+ 'xmlcast',
+ 'xmlcomment',
+ 'xmlconcat',
+ 'xmldocument',
+ 'xmlelement',
+ 'xmlexists',
+ 'xmlforest',
+ 'xmliterate',
+ 'xmlnamespaces',
+ 'xmlparse',
+ 'xmlpi',
+ 'xmlquery',
+ 'xmlserialize',
+ 'xmltable',
+ 'xmltext',
+ 'xmlvalidate',
+ 'year',
+ 'zone',
+)
+
+_KEYWORDS_ODBC = (
+ 'absolute',
+ 'action',
+ 'ada',
+ 'add',
+ 'all',
+ 'allocate',
+ 'alter',
+ 'and',
+ 'any',
+ 'are',
+ 'as',
+ 'asc',
+ 'assertion',
+ 'at',
+ 'authorization',
+ 'avg',
+ 'begin',
+ 'between',
+ 'bit',
+ 'bit_length',
+ 'both',
+ 'by',
+ 'cascade',
+ 'cascaded',
+ 'case',
+ 'cast',
+ 'catalog',
+ 'char',
+ 'char_length',
+ 'character',
+ 'character_length',
+ 'check',
+ 'close',
+ 'coalesce',
+ 'collate',
+ 'collation',
+ 'column',
+ 'commit',
+ 'connect',
+ 'connection',
+ 'constraint',
+ 'constraints',
+ 'continue',
+ 'convert',
+ 'corresponding',
+ 'count',
+ 'create',
+ 'cross',
+ 'current',
+ 'current_date',
+ 'current_time',
+ 'current_timestamp',
+ 'current_user',
+ 'cursor',
+ 'date',
+ 'day',
+ 'deallocate',
+ 'dec',
+ 'decimal',
+ 'declare',
+ 'default',
+ 'deferrable',
+ 'deferred',
+ 'delete',
+ 'desc',
+ 'describe',
+ 'descriptor',
+ 'diagnostics',
+ 'disconnect',
+ 'distinct',
+ 'domain',
+ 'double',
+ 'drop',
+ 'else',
+ 'end',
+ 'end-exec',
+ 'escape',
+ 'except',
+ 'exception',
+ 'exec',
+ 'execute',
+ 'exists',
+ 'external',
+ 'extract',
+ 'false',
+ 'fetch',
+ 'first',
+ 'float',
+ 'for',
+ 'foreign',
+ 'fortran',
+ 'found',
+ 'from',
+ 'full',
+ 'get',
+ 'global',
+ 'go',
+ 'goto',
+ 'grant',
+ 'group',
+ 'having',
+ 'hour',
+ 'identity',
+ 'immediate',
+ 'in',
+ 'include',
+ 'index',
+ 'indicator',
+ 'initially',
+ 'inner',
+ 'input',
+ 'insensitive',
+ 'insert',
+ 'int',
+ 'integer',
+ 'intersect',
+ 'interval',
+ 'into',
+ 'is',
+ 'isolation',
+ 'join',
+ 'key',
+ 'language',
+ 'last',
+ 'leading',
+ 'left',
+ 'level',
+ 'like',
+ 'local',
+ 'lower',
+ 'match',
+ 'max',
+ 'min',
+ 'minute',
+ 'module',
+ 'month',
+ 'names',
+ 'national',
+ 'natural',
+ 'nchar',
+ 'next',
+ 'no',
+ 'none',
+ 'not',
+ 'null',
+ 'nullif',
+ 'numeric',
+ 'octet_length',
+ 'of',
+ 'on',
+ 'only',
+ 'open',
+ 'option',
+ 'or',
+ 'order',
+ 'outer',
+ 'output',
+ 'overlaps',
+ 'pad',
+ 'partial',
+ 'pascal',
+ 'position',
+ 'precision',
+ 'prepare',
+ 'preserve',
+ 'primary',
+ 'prior',
+ 'privileges',
+ 'procedure',
+ 'public',
+ 'read',
+ 'real',
+ 'references',
+ 'relative',
+ 'restrict',
+ 'revoke',
+ 'right',
+ 'rollback',
+ 'rows',
+ 'schema',
+ 'scroll',
+ 'second',
+ 'section',
+ 'select',
+ 'session',
+ 'session_user',
+ 'set',
+ 'size',
+ 'smallint',
+ 'some',
+ 'space',
+ 'sql',
+ 'sqlca',
+ 'sqlcode',
+ 'sqlerror',
+ 'sqlstate',
+ 'sqlwarning',
+ 'substring',
+ 'sum',
+ 'system_user',
+ 'table',
+ 'temporary',
+ 'then',
+ 'time',
+ 'timestamp',
+ 'timezone_hour',
+ 'timezone_minute',
+ 'to',
+ 'trailing',
+ 'transaction',
+ 'translate',
+ 'translation',
+ 'trim',
+ 'true',
+ 'union',
+ 'unique',
+ 'unknown',
+ 'update',
+ 'upper',
+ 'usage',
+ 'user',
+ 'using',
+ 'value',
+ 'values',
+ 'varchar',
+ 'varying',
+ 'view',
+ 'when',
+ 'whenever',
+ 'where',
+ 'with',
+ 'work',
+ 'write',
+ 'year',
+ 'zone',
+)
+
+# See https://msdn.microsoft.com/en-us/library/ms189822.aspx.
+KEYWORDS = sorted(set(_KEYWORDS_FUTURE + _KEYWORDS_ODBC + _KEYWORDS_SERVER))
+
+# See https://msdn.microsoft.com/en-us/library/ms187752.aspx.
+TYPES = (
+ 'bigint',
+ 'binary',
+ 'bit',
+ 'char',
+ 'cursor',
+ 'date',
+ 'datetime',
+ 'datetime2',
+ 'datetimeoffset',
+ 'decimal',
+ 'float',
+ 'hierarchyid',
+ 'image',
+ 'int',
+ 'money',
+ 'nchar',
+ 'ntext',
+ 'numeric',
+ 'nvarchar',
+ 'real',
+ 'smalldatetime',
+ 'smallint',
+ 'smallmoney',
+ 'sql_variant',
+ 'table',
+ 'text',
+ 'time',
+ 'timestamp',
+ 'tinyint',
+ 'uniqueidentifier',
+ 'varbinary',
+ 'varchar',
+ 'xml',
+)
+
+# See https://msdn.microsoft.com/en-us/library/ms174318.aspx.
+FUNCTIONS = (
+ '$partition',
+ 'abs',
+ 'acos',
+ 'app_name',
+ 'applock_mode',
+ 'applock_test',
+ 'ascii',
+ 'asin',
+ 'assemblyproperty',
+ 'atan',
+ 'atn2',
+ 'avg',
+ 'binary_checksum',
+ 'cast',
+ 'ceiling',
+ 'certencoded',
+ 'certprivatekey',
+ 'char',
+ 'charindex',
+ 'checksum',
+ 'checksum_agg',
+ 'choose',
+ 'col_length',
+ 'col_name',
+ 'columnproperty',
+ 'compress',
+ 'concat',
+ 'connectionproperty',
+ 'context_info',
+ 'convert',
+ 'cos',
+ 'cot',
+ 'count',
+ 'count_big',
+ 'current_request_id',
+ 'current_timestamp',
+ 'current_transaction_id',
+ 'current_user',
+ 'cursor_status',
+ 'database_principal_id',
+ 'databasepropertyex',
+ 'dateadd',
+ 'datediff',
+ 'datediff_big',
+ 'datefromparts',
+ 'datename',
+ 'datepart',
+ 'datetime2fromparts',
+ 'datetimefromparts',
+ 'datetimeoffsetfromparts',
+ 'day',
+ 'db_id',
+ 'db_name',
+ 'decompress',
+ 'degrees',
+ 'dense_rank',
+ 'difference',
+ 'eomonth',
+ 'error_line',
+ 'error_message',
+ 'error_number',
+ 'error_procedure',
+ 'error_severity',
+ 'error_state',
+ 'exp',
+ 'file_id',
+ 'file_idex',
+ 'file_name',
+ 'filegroup_id',
+ 'filegroup_name',
+ 'filegroupproperty',
+ 'fileproperty',
+ 'floor',
+ 'format',
+ 'formatmessage',
+ 'fulltextcatalogproperty',
+ 'fulltextserviceproperty',
+ 'get_filestream_transaction_context',
+ 'getansinull',
+ 'getdate',
+ 'getutcdate',
+ 'grouping',
+ 'grouping_id',
+ 'has_perms_by_name',
+ 'host_id',
+ 'host_name',
+ 'iif',
+ 'index_col',
+ 'indexkey_property',
+ 'indexproperty',
+ 'is_member',
+ 'is_rolemember',
+ 'is_srvrolemember',
+ 'isdate',
+ 'isjson',
+ 'isnull',
+ 'isnumeric',
+ 'json_modify',
+ 'json_query',
+ 'json_value',
+ 'left',
+ 'len',
+ 'log',
+ 'log10',
+ 'lower',
+ 'ltrim',
+ 'max',
+ 'min',
+ 'min_active_rowversion',
+ 'month',
+ 'nchar',
+ 'newid',
+ 'newsequentialid',
+ 'ntile',
+ 'object_definition',
+ 'object_id',
+ 'object_name',
+ 'object_schema_name',
+ 'objectproperty',
+ 'objectpropertyex',
+ 'opendatasource',
+ 'openjson',
+ 'openquery',
+ 'openrowset',
+ 'openxml',
+ 'original_db_name',
+ 'original_login',
+ 'parse',
+ 'parsename',
+ 'patindex',
+ 'permissions',
+ 'pi',
+ 'power',
+ 'pwdcompare',
+ 'pwdencrypt',
+ 'quotename',
+ 'radians',
+ 'rand',
+ 'rank',
+ 'replace',
+ 'replicate',
+ 'reverse',
+ 'right',
+ 'round',
+ 'row_number',
+ 'rowcount_big',
+ 'rtrim',
+ 'schema_id',
+ 'schema_name',
+ 'scope_identity',
+ 'serverproperty',
+ 'session_context',
+ 'session_user',
+ 'sign',
+ 'sin',
+ 'smalldatetimefromparts',
+ 'soundex',
+ 'sp_helplanguage',
+ 'space',
+ 'sqrt',
+ 'square',
+ 'stats_date',
+ 'stdev',
+ 'stdevp',
+ 'str',
+ 'string_escape',
+ 'string_split',
+ 'stuff',
+ 'substring',
+ 'sum',
+ 'suser_id',
+ 'suser_name',
+ 'suser_sid',
+ 'suser_sname',
+ 'switchoffset',
+ 'sysdatetime',
+ 'sysdatetimeoffset',
+ 'system_user',
+ 'sysutcdatetime',
+ 'tan',
+ 'textptr',
+ 'textvalid',
+ 'timefromparts',
+ 'todatetimeoffset',
+ 'try_cast',
+ 'try_convert',
+ 'try_parse',
+ 'type_id',
+ 'type_name',
+ 'typeproperty',
+ 'unicode',
+ 'upper',
+ 'user_id',
+ 'user_name',
+ 'var',
+ 'varp',
+ 'xact_state',
+ 'year',
+)
diff --git a/pygments/lexers/asm.py b/pygments/lexers/asm.py
index 325cbbed..2bb3eac9 100644
--- a/pygments/lexers/asm.py
+++ b/pygments/lexers/asm.py
@@ -20,7 +20,7 @@ from pygments.token import Text, Name, Number, String, Comment, Punctuation, \
__all__ = ['GasLexer', 'ObjdumpLexer', 'DObjdumpLexer', 'CppObjdumpLexer',
'CObjdumpLexer', 'HsailLexer', 'LlvmLexer', 'NasmLexer',
- 'NasmObjdumpLexer', 'Ca65Lexer']
+ 'NasmObjdumpLexer', 'TasmLexer', 'Ca65Lexer']
class GasLexer(RegexLexer):
@@ -424,7 +424,6 @@ class LlvmLexer(RegexLexer):
]
}
-
class NasmLexer(RegexLexer):
"""
For Nasm (Intel) assembly code.
@@ -512,6 +511,86 @@ class NasmObjdumpLexer(ObjdumpLexer):
tokens = _objdump_lexer_tokens(NasmLexer)
+class TasmLexer(RegexLexer):
+ """
+ For Tasm (Turbo Assembler) assembly code.
+ """
+ name = 'TASM'
+ aliases = ['tasm']
+ filenames = ['*.asm', '*.ASM', '*.tasm']
+ mimetypes = ['text/x-tasm']
+
+ identifier = r'[@a-z$._?][\w$.?#@~]*'
+ hexn = r'(?:0x[0-9a-f]+|$0[0-9a-f]*|[0-9]+[0-9a-f]*h)'
+ octn = r'[0-7]+q'
+ binn = r'[01]+b'
+ decn = r'[0-9]+'
+ floatn = decn + r'\.e?' + decn
+ string = r'"(\\"|[^"\n])*"|' + r"'(\\'|[^'\n])*'|" + r"`(\\`|[^`\n])*`"
+ declkw = r'(?:res|d)[bwdqt]|times'
+ register = (r'r[0-9][0-5]?[bwd]|'
+ r'[a-d][lh]|[er]?[a-d]x|[er]?[sb]p|[er]?[sd]i|[c-gs]s|st[0-7]|'
+ r'mm[0-7]|cr[0-4]|dr[0-367]|tr[3-7]')
+ wordop = r'seg|wrt|strict'
+ type = r'byte|[dq]?word'
+ directives = (r'BITS|USE16|USE32|SECTION|SEGMENT|ABSOLUTE|EXTERN|GLOBAL|'
+ r'ORG|ALIGN|STRUC|ENDSTRUC|ENDS|COMMON|CPU|GROUP|UPPERCASE|INCLUDE|'
+ r'EXPORT|LIBRARY|MODULE|PROC|ENDP|USES|ARG|DATASEG|UDATASEG|END|IDEAL|'
+ r'P386|MODEL|ASSUME|CODESEG|SIZE')
+ # T[A-Z][a-z] is more of a convention. Lexer should filter out STRUC definitions
+ # and then 'add' them to datatype somehow.
+ datatype = (r'db|dd|dw|T[A-Z][a-z]+')
+
+ flags = re.IGNORECASE | re.MULTILINE
+ tokens = {
+ 'root': [
+ (r'^\s*%', Comment.Preproc, 'preproc'),
+ include('whitespace'),
+ (identifier + ':', Name.Label),
+ (directives, Keyword, 'instruction-args'),
+ (r'(%s)(\s+)(%s)' % (identifier, datatype),
+ bygroups(Name.Constant, Keyword.Declaration, Keyword.Declaration),
+ 'instruction-args'),
+ (declkw, Keyword.Declaration, 'instruction-args'),
+ (identifier, Name.Function, 'instruction-args'),
+ (r'[\r\n]+', Text)
+ ],
+ 'instruction-args': [
+ (string, String),
+ (hexn, Number.Hex),
+ (octn, Number.Oct),
+ (binn, Number.Bin),
+ (floatn, Number.Float),
+ (decn, Number.Integer),
+ include('punctuation'),
+ (register, Name.Builtin),
+ (identifier, Name.Variable),
+ # Do not match newline when it's preceeded by a backslash
+ (r'(\\\s*)(;.*)([\r\n])', bygroups(Text, Comment.Single, Text)),
+ (r'[\r\n]+', Text, '#pop'),
+ include('whitespace')
+ ],
+ 'preproc': [
+ (r'[^;\n]+', Comment.Preproc),
+ (r';.*?\n', Comment.Single, '#pop'),
+ (r'\n', Comment.Preproc, '#pop'),
+ ],
+ 'whitespace': [
+ (r'[\n\r]', Text),
+ (r'\\[\n\r]', Text),
+ (r'[ \t]+', Text),
+ (r';.*', Comment.Single)
+ ],
+ 'punctuation': [
+ (r'[,():\[\]]+', Punctuation),
+ (r'[&|^<>+*=/%~-]+', Operator),
+ (r'[$]+', Keyword.Constant),
+ (wordop, Operator.Word),
+ (type, Keyword.Type)
+ ],
+ }
+
+
class Ca65Lexer(RegexLexer):
"""
For ca65 assembler sources.
diff --git a/pygments/lexers/bibtex.py b/pygments/lexers/bibtex.py
new file mode 100644
index 00000000..cbaedca2
--- /dev/null
+++ b/pygments/lexers/bibtex.py
@@ -0,0 +1,156 @@
+# -*- coding: utf-8 -*-
+"""
+ pygments.lexers.bibtex
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+ Lexers for BibTeX bibliography data and styles
+
+ :copyright: Copyright 2005-2015 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+
+from pygments.lexer import RegexLexer, ExtendedRegexLexer, include, default, words
+from pygments.token import Name, Comment, String, Error, Number, Text, Keyword, Punctuation
+
+__all__ = ['BibTeXLexer', 'BSTLexer']
+
+
+class BibTeXLexer(ExtendedRegexLexer):
+ """
+ A lexer for BibTeX bibliography data format.
+
+ .. versionadded:: 2.2
+ """
+
+ name = 'BibTeX'
+ aliases = ['bib', 'bibtex']
+ filenames = ['*.bib']
+ mimetypes = ["text/x-bibtex"]
+ flags = re.IGNORECASE
+
+ ALLOWED_CHARS = r'@!$&*+\-./:;<>?\[\\\]^`|~'
+ IDENTIFIER = '[{0}][{1}]*'.format('a-z_' + ALLOWED_CHARS, r'\w' + ALLOWED_CHARS)
+
+ def open_brace_callback(self, match, ctx):
+ opening_brace = match.group()
+ ctx.opening_brace = opening_brace
+ yield match.start(), Punctuation, opening_brace
+ ctx.pos = match.end()
+
+ def close_brace_callback(self, match, ctx):
+ closing_brace = match.group()
+ if (
+ ctx.opening_brace == '{' and closing_brace != '}' or
+ ctx.opening_brace == '(' and closing_brace != ')'
+ ):
+ yield match.start(), Error, closing_brace
+ else:
+ yield match.start(), Punctuation, closing_brace
+ del ctx.opening_brace
+ ctx.pos = match.end()
+
+ tokens = {
+ 'root': [
+ include('whitespace'),
+ ('@comment', Comment),
+ ('@preamble', Name.Class, ('closing-brace', 'value', 'opening-brace')),
+ ('@string', Name.Class, ('closing-brace', 'field', 'opening-brace')),
+ ('@' + IDENTIFIER, Name.Class, ('closing-brace', 'command-body', 'opening-brace')),
+ ('.+', Comment),
+ ],
+ 'opening-brace': [
+ include('whitespace'),
+ (r'[{(]', open_brace_callback, '#pop'),
+ ],
+ 'closing-brace': [
+ include('whitespace'),
+ (r'[})]', close_brace_callback, '#pop'),
+ ],
+ 'command-body': [
+ include('whitespace'),
+ (r'[^\s\,\}]+', Name.Label, ('#pop', 'fields')),
+ ],
+ 'fields': [
+ include('whitespace'),
+ (',', Punctuation, 'field'),
+ default('#pop'),
+ ],
+ 'field': [
+ include('whitespace'),
+ (IDENTIFIER, Name.Attribute, ('value', '=')),
+ default('#pop'),
+ ],
+ '=': [
+ include('whitespace'),
+ ('=', Punctuation, '#pop'),
+ ],
+ 'value': [
+ include('whitespace'),
+ (IDENTIFIER, Name.Variable),
+ ('"', String, 'quoted-string'),
+ (r'\{', String, 'braced-string'),
+ (r'[\d]+', Number),
+ ('#', Punctuation),
+ default('#pop'),
+ ],
+ 'quoted-string': [
+ (r'\{', String, 'braced-string'),
+ ('"', String, '#pop'),
+ ('[^\{\"]+', String),
+ ],
+ 'braced-string': [
+ (r'\{', String, '#push'),
+ (r'\}', String, '#pop'),
+ ('[^\{\}]+', String),
+ ],
+ 'whitespace': [
+ (r'\s+', Text),
+ ],
+ }
+
+
+class BSTLexer(RegexLexer):
+ """
+ A lexer for BibTeX bibliography styles.
+
+ .. versionadded:: 2.2
+ """
+
+ name = 'BST'
+ aliases = ['bst', 'bst-pybtex']
+ filenames = ['*.bst']
+ flags = re.IGNORECASE | re.MULTILINE
+
+ tokens = {
+ 'root': [
+ include('whitespace'),
+ (words(['read', 'sort']), Keyword),
+ (words(['execute', 'integers', 'iterate', 'reverse', 'strings']), Keyword, ('group')),
+ (words(['function', 'macro']), Keyword, ('group', 'group')),
+ (words(['entry']), Keyword, ('group', 'group', 'group')),
+ ],
+ 'group': [
+ include('whitespace'),
+ (r'\{', Punctuation, ('#pop', 'group-end', 'body')),
+ ],
+ 'group-end': [
+ include('whitespace'),
+ (r'\}', Punctuation, '#pop'),
+ ],
+ 'body': [
+ include('whitespace'),
+ (r"\'[^#\"\{\}\s]+", Name.Function),
+ (r'[^#\"\{\}\s]+\$', Name.Builtin),
+ (r'[^#\"\{\}\s]+', Name.Variable),
+ (r'"[^\"]*"', String),
+ (r'#-?\d+', Number),
+ (r'\{', Punctuation, ('group-end', 'body')),
+ default('#pop'),
+ ],
+ 'whitespace': [
+ ('\s+', Text),
+ ('%.*?$', Comment.SingleLine),
+ ],
+ }
diff --git a/pygments/lexers/compiled.py b/pygments/lexers/compiled.py
index 1cf83d7f..b6673437 100644
--- a/pygments/lexers/compiled.py
+++ b/pygments/lexers/compiled.py
@@ -29,5 +29,6 @@ from pygments.lexers.dylan import DylanLexer, DylanLidLexer, DylanConsoleLexer
from pygments.lexers.ooc import OocLexer
from pygments.lexers.felix import FelixLexer
from pygments.lexers.nimrod import NimrodLexer
+from pygments.lexers.crystal import CrystalLexer
__all__ = []
diff --git a/pygments/lexers/crystal.py b/pygments/lexers/crystal.py
new file mode 100644
index 00000000..78c70b61
--- /dev/null
+++ b/pygments/lexers/crystal.py
@@ -0,0 +1,384 @@
+# -*- coding: utf-8 -*-
+"""
+ pygments.lexers.crystal
+ ~~~~~~~~~~~~~~~~~~~~~~~
+
+ Lexer for Crystal.
+
+ :copyright: Copyright 2006-2016 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+
+from pygments.lexer import Lexer, RegexLexer, ExtendedRegexLexer, include, \
+ bygroups, default, LexerContext, do_insertions, words
+from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
+ Number, Punctuation, Error, Generic
+from pygments.util import shebang_matches
+
+__all__ = ['CrystalLexer']
+
+line_re = re.compile('.*?\n')
+
+
+
+
+CRYSTAL_OPERATORS = [
+ '!=', '!~', '!', '%', '&&', '&', '**', '*', '+', '-', '/', '<=>', '<<', '<=', '<',
+ '===', '==', '=~', '=', '>=', '>>', '>', '[]=', '[]?', '[]', '^', '||', '|', '~'
+]
+
+
+class CrystalLexer(ExtendedRegexLexer):
+ """
+ For `Crystal <http://crystal-lang.org>`_ source code.
+ """
+
+ name = 'Crystal'
+ aliases = ['cr', 'crystal']
+ filenames = ['*.cr']
+ mimetypes = ['text/x-crystal']
+
+ flags = re.DOTALL | re.MULTILINE
+
+ def heredoc_callback(self, match, ctx):
+ # okay, this is the hardest part of parsing Crystal...
+ # match: 1 = <<-?, 2 = quote? 3 = name 4 = quote? 5 = rest of line
+
+ start = match.start(1)
+ yield start, Operator, match.group(1) # <<-?
+ yield match.start(2), String.Heredoc, match.group(2) # quote ", ', `
+ yield match.start(3), String.Delimiter, match.group(3) # heredoc name
+ yield match.start(4), String.Heredoc, match.group(4) # quote again
+
+ heredocstack = ctx.__dict__.setdefault('heredocstack', [])
+ outermost = not bool(heredocstack)
+ heredocstack.append((match.group(1) == '<<-', match.group(3)))
+
+ ctx.pos = match.start(5)
+ ctx.end = match.end(5)
+ # this may find other heredocs
+ for i, t, v in self.get_tokens_unprocessed(context=ctx):
+ yield i, t, v
+ ctx.pos = match.end()
+
+ if outermost:
+ # this is the outer heredoc again, now we can process them all
+ for tolerant, hdname in heredocstack:
+ lines = []
+ for match in line_re.finditer(ctx.text, ctx.pos):
+ if tolerant:
+ check = match.group().strip()
+ else:
+ check = match.group().rstrip()
+ if check == hdname:
+ for amatch in lines:
+ yield amatch.start(), String.Heredoc, amatch.group()
+ yield match.start(), String.Delimiter, match.group()
+ ctx.pos = match.end()
+ break
+ else:
+ lines.append(match)
+ else:
+ # end of heredoc not found -- error!
+ for amatch in lines:
+ yield amatch.start(), Error, amatch.group()
+ ctx.end = len(ctx.text)
+ del heredocstack[:]
+
+ def gen_crystalstrings_rules():
+ def intp_regex_callback(self, match, ctx):
+ yield match.start(1), String.Regex, match.group(1) # begin
+ nctx = LexerContext(match.group(3), 0, ['interpolated-regex'])
+ for i, t, v in self.get_tokens_unprocessed(context=nctx):
+ yield match.start(3)+i, t, v
+ yield match.start(4), String.Regex, match.group(4) # end[imsx]*
+ ctx.pos = match.end()
+
+ def intp_string_callback(self, match, ctx):
+ yield match.start(1), String.Other, match.group(1)
+ nctx = LexerContext(match.group(3), 0, ['interpolated-string'])
+ for i, t, v in self.get_tokens_unprocessed(context=nctx):
+ yield match.start(3)+i, t, v
+ yield match.start(4), String.Other, match.group(4) # end
+ ctx.pos = match.end()
+
+ states = {}
+ states['strings'] = [
+ (r'\:@{0,2}[a-zA-Z_]\w*[!?]?', String.Symbol),
+ (words(CRYSTAL_OPERATORS, prefix=r'\:@{0,2}'), String.Symbol),
+ (r":'(\\\\|\\'|[^'])*'", String.Symbol),
+ # This allows arbitrary text after '\ for simplicity
+ (r"'(\\\\|\\'|[^']|\\[^'\\]+)'", String.Char),
+ (r':"', String.Symbol, 'simple-sym'),
+ # Crystal doesn't have "symbol:"s but this simplifies function args
+ (r'([a-zA-Z_]\w*)(:)(?!:)', bygroups(String.Symbol, Punctuation)),
+ (r'"', String.Double, 'simple-string'),
+ (r'(?<!\.)`', String.Backtick, 'simple-backtick'),
+ ]
+
+ # double-quoted string and symbol
+ for name, ttype, end in ('string', String.Double, '"'), \
+ ('sym', String.Symbol, '"'), \
+ ('backtick', String.Backtick, '`'):
+ states['simple-'+name] = [
+ include('string-escaped' if name == 'sym' else 'string-intp-escaped'),
+ (r'[^\\%s#]+' % end, ttype),
+ (r'[\\#]', ttype),
+ (end, ttype, '#pop'),
+ ]
+
+ # braced quoted strings
+ for lbrace, rbrace, bracecc, name in \
+ ('\\{', '\\}', '{}', 'cb'), \
+ ('\\[', '\\]', '\\[\\]', 'sb'), \
+ ('\\(', '\\)', '()', 'pa'), \
+ ('<', '>', '<>', 'ab'):
+ states[name+'-intp-string'] = [
+ (r'\\[' + lbrace + ']', String.Other),
+ (lbrace, String.Other, '#push'),
+ (rbrace, String.Other, '#pop'),
+ include('string-intp-escaped'),
+ (r'[\\#' + bracecc + ']', String.Other),
+ (r'[^\\#' + bracecc + ']+', String.Other),
+ ]
+ states['strings'].append((r'%' + lbrace, String.Other,
+ name+'-intp-string'))
+ states[name+'-string'] = [
+ (r'\\[\\' + bracecc + ']', String.Other),
+ (lbrace, String.Other, '#push'),
+ (rbrace, String.Other, '#pop'),
+ (r'[\\#' + bracecc + ']', String.Other),
+ (r'[^\\#' + bracecc + ']+', String.Other),
+ ]
+ # http://crystal-lang.org/docs/syntax_and_semantics/literals/array.html
+ states['strings'].append((r'%[wi]' + lbrace, String.Other,
+ name+'-string'))
+ states[name+'-regex'] = [
+ (r'\\[\\' + bracecc + ']', String.Regex),
+ (lbrace, String.Regex, '#push'),
+ (rbrace + '[imsx]*', String.Regex, '#pop'),
+ include('string-intp'),
+ (r'[\\#' + bracecc + ']', String.Regex),
+ (r'[^\\#' + bracecc + ']+', String.Regex),
+ ]
+ states['strings'].append((r'%r' + lbrace, String.Regex,
+ name+'-regex'))
+
+ # these must come after %<brace>!
+ states['strings'] += [
+ # %r regex
+ (r'(%r([\W_]))((?:\\\2|(?!\2).)*)(\2[imsx]*)',
+ intp_regex_callback),
+ # regular fancy strings with qsw
+ (r'(%[wi]([\W_]))((?:\\\2|(?!\2).)*)(\2)',
+ intp_string_callback),
+ # special forms of fancy strings after operators or
+ # in method calls with braces
+ (r'(?<=[-+/*%=<>&!^|~,(])(\s*)(%([\t ])(?:(?:\\\3|(?!\3).)*)\3)',
+ bygroups(Text, String.Other, None)),
+ # and because of fixed width lookbehinds the whole thing a
+ # second time for line startings...
+ (r'^(\s*)(%([\t ])(?:(?:\\\3|(?!\3).)*)\3)',
+ bygroups(Text, String.Other, None)),
+ # all regular fancy strings without qsw
+ (r'(%([\[{(<]))((?:\\\2|(?!\2).)*)(\2)',
+ intp_string_callback),
+ ]
+
+ return states
+
+ tokens = {
+ 'root': [
+ (r'#.*?$', Comment.Single),
+ # keywords
+ (words('''
+ abstract asm as begin break case do else elsif end ensure extend ifdef if
+ include instance_sizeof next of pointerof private protected rescue return
+ require sizeof super then typeof unless until when while with yield
+ '''.split(), suffix=r'\b'), Keyword),
+ (words(['true', 'false', 'nil'], suffix=r'\b'), Keyword.Constant),
+ # start of function, class and module names
+ (r'(module|lib)(\s+)([a-zA-Z_]\w*(?:::[a-zA-Z_]\w*)*)',
+ bygroups(Keyword, Text, Name.Namespace)),
+ (r'(def|fun|macro)(\s+)((?:[a-zA-Z_]\w*::)*)',
+ bygroups(Keyword, Text, Name.Namespace), 'funcname'),
+ (r'def(?=[*%&^`~+-/\[<>=])', Keyword, 'funcname'),
+ (r'(class|struct|union|type|alias|enum)(\s+)((?:[a-zA-Z_]\w*::)*)',
+ bygroups(Keyword, Text, Name.Namespace), 'classname'),
+ (r'(self|out|uninitialized)\b|(is_a|responds_to)\?', Keyword.Pseudo),
+ # macros
+ (words('''
+ debugger record pp assert_responds_to spawn parallel
+ getter setter property delegate def_hash def_equals def_equals_and_hash forward_missing_to
+ '''.split(), suffix=r'\b'), Name.Builtin.Pseudo),
+ (r'getter[!?]|property[!?]|__(DIR|FILE|LINE)__\b', Name.Builtin.Pseudo),
+ # builtins
+ # http://crystal-lang.org/api/toplevel.html
+ (words('''
+ Object Value Struct Reference Proc Class Nil Symbol Enum Void
+ Bool Number Int Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Float Float32 Float64 Char String
+ Pointer Slice Range Exception Regex
+ Mutex StaticArray Array Hash Set Tuple Deque Box Process File Dir Time Channel Concurrent Scheduler
+ abort at_exit caller delay exit fork future get_stack_top gets lazy loop main p print printf puts
+ raise rand read_line sleep sprintf system with_color
+ '''.split(), prefix=r'(?<!\.)', suffix=r'\b'), Name.Builtin),
+ # normal heredocs
+ (r'(?<!\w)(<<-?)(["`\']?)([a-zA-Z_]\w*)(\2)(.*?\n)',
+ heredoc_callback),
+ # empty string heredocs
+ (r'(<<-?)("|\')()(\2)(.*?\n)', heredoc_callback),
+ (r'__END__', Comment.Preproc, 'end-part'),
+ # multiline regex (after keywords or assignments)
+ (r'(?:^|(?<=[=<>~!:])|'
+ r'(?<=(?:\s|;)when\s)|'
+ r'(?<=(?:\s|;)or\s)|'
+ r'(?<=(?:\s|;)and\s)|'
+ r'(?<=\.index\s)|'
+ r'(?<=\.scan\s)|'
+ r'(?<=\.sub\s)|'
+ r'(?<=\.sub!\s)|'
+ r'(?<=\.gsub\s)|'
+ r'(?<=\.gsub!\s)|'
+ r'(?<=\.match\s)|'
+ r'(?<=(?:\s|;)if\s)|'
+ r'(?<=(?:\s|;)elsif\s)|'
+ r'(?<=^when\s)|'
+ r'(?<=^index\s)|'
+ r'(?<=^scan\s)|'
+ r'(?<=^sub\s)|'
+ r'(?<=^gsub\s)|'
+ r'(?<=^sub!\s)|'
+ r'(?<=^gsub!\s)|'
+ r'(?<=^match\s)|'
+ r'(?<=^if\s)|'
+ r'(?<=^elsif\s)'
+ r')(\s*)(/)', bygroups(Text, String.Regex), 'multiline-regex'),
+ # multiline regex (in method calls or subscripts)
+ (r'(?<=\(|,|\[)/', String.Regex, 'multiline-regex'),
+ # multiline regex (this time the funny no whitespace rule)
+ (r'(\s+)(/)(?![\s=])', bygroups(Text, String.Regex),
+ 'multiline-regex'),
+ # lex numbers and ignore following regular expressions which
+ # are division operators in fact (grrrr. i hate that. any
+ # better ideas?)
+ # since pygments 0.7 we also eat a "?" operator after numbers
+ # so that the char operator does not work. Chars are not allowed
+ # there so that you can use the ternary operator.
+ # stupid example:
+ # x>=0?n[x]:""
+ (r'(0o[0-7]+(?:_[0-7]+)*(?:_?[iu][0-9]+)?)\b(\s*)([/?])?',
+ bygroups(Number.Oct, Text, Operator)),
+ (r'(0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*(?:_?[iu][0-9]+)?)\b(\s*)([/?])?',
+ bygroups(Number.Hex, Text, Operator)),
+ (r'(0b[01]+(?:_[01]+)*(?:_?[iu][0-9]+)?)\b(\s*)([/?])?',
+ bygroups(Number.Bin, Text, Operator)),
+ # 3 separate expressions for floats because any of the 3 optional parts makes it a float
+ (r'((?:0(?![0-9])|[1-9][\d_]*)(?:\.\d[\d_]*)(?:e[+-]?[0-9]+)?(?:_?[f][0-9]+)?)(\s*)([/?])?',
+ bygroups(Number.Float, Text, Operator)),
+ (r'((?:0(?![0-9])|[1-9][\d_]*)(?:\.\d[\d_]*)?(?:e[+-]?[0-9]+)(?:_?[f][0-9]+)?)(\s*)([/?])?',
+ bygroups(Number.Float, Text, Operator)),
+ (r'((?:0(?![0-9])|[1-9][\d_]*)(?:\.\d[\d_]*)?(?:e[+-]?[0-9]+)?(?:_?[f][0-9]+))(\s*)([/?])?',
+ bygroups(Number.Float, Text, Operator)),
+ (r'(0\b|[1-9][\d]*(?:_\d+)*(?:_?[iu][0-9]+)?)\b(\s*)([/?])?',
+ bygroups(Number.Integer, Text, Operator)),
+ # Names
+ (r'@@[a-zA-Z_]\w*', Name.Variable.Class),
+ (r'@[a-zA-Z_]\w*', Name.Variable.Instance),
+ (r'\$\w+', Name.Variable.Global),
+ (r'\$[!@&`\'+~=/\\,;.<>_*$?:"^-]', Name.Variable.Global),
+ (r'\$-[0adFiIlpvw]', Name.Variable.Global),
+ (r'::', Operator),
+ include('strings'),
+ # chars
+ (r'\?(\\[MC]-)*' # modifiers
+ r'(\\([\\befnrtv#"\']|x[a-fA-F0-9]{1,2}|[0-7]{1,3})|\S)'
+ r'(?!\w)',
+ String.Char),
+ (r'[A-Z][A-Z_]+\b', Name.Constant),
+ # macro expansion
+ (r'\{%', String.Interpol, 'in-macro-control'),
+ (r'\{\{', String.Interpol, 'in-macro-expr'),
+ # attributes
+ (r'(@\[)(\s*)([A-Z]\w*)', bygroups(Operator, Text, Name.Decorator), 'in-attr'),
+ # this is needed because Crystal attributes can look
+ # like keywords (class) or like this: ` ?!?
+ (words(CRYSTAL_OPERATORS, prefix=r'(\.|::)'),
+ bygroups(Operator, Name.Operator)),
+ (r'(\.|::)([a-zA-Z_]\w*[!?]?|[*%&^`~+\-/\[<>=])',
+ bygroups(Operator, Name)),
+ # Names can end with [!?] unless it's "!="
+ (r'[a-zA-Z_]\w*(?:[!?](?!=))?', Name),
+ (r'(\[|\]\??|\*\*|<=>?|>=|<<?|>>?|=~|===|'
+ r'!~|&&?|\|\||\.{1,3})', Operator),
+ (r'[-+/*%=<>&!^|~]=?', Operator),
+ (r'[(){};,/?:\\]', Punctuation),
+ (r'\s+', Text)
+ ],
+ 'funcname': [
+ (r'(?:([a-zA-Z_]\w*)(\.))?'
+ r'([a-zA-Z_]\w*[!?]?|\*\*?|[-+]@?|'
+ r'[/%&|^`~]|\[\]=?|<<|>>|<=?>|>=?|===?)',
+ bygroups(Name.Class, Operator, Name.Function), '#pop'),
+ default('#pop')
+ ],
+ 'classname': [
+ (r'[A-Z_]\w*', Name.Class),
+ (r'(\()(\s*)([A-Z_]\w*)(\s*)(\))', bygroups(Punctuation, Text, Name.Class, Text, Punctuation)),
+ default('#pop')
+ ],
+ 'in-intp': [
+ (r'\{', String.Interpol, '#push'),
+ (r'\}', String.Interpol, '#pop'),
+ include('root'),
+ ],
+ 'string-intp': [
+ (r'#\{', String.Interpol, 'in-intp'),
+ ],
+ 'string-escaped': [
+ (r'\\([\\befnstv#"\']|x[a-fA-F0-9]{1,2}|[0-7]{1,3})', String.Escape)
+ ],
+ 'string-intp-escaped': [
+ include('string-intp'),
+ include('string-escaped'),
+ ],
+ 'interpolated-regex': [
+ include('string-intp'),
+ (r'[\\#]', String.Regex),
+ (r'[^\\#]+', String.Regex),
+ ],
+ 'interpolated-string': [
+ include('string-intp'),
+ (r'[\\#]', String.Other),
+ (r'[^\\#]+', String.Other),
+ ],
+ 'multiline-regex': [
+ include('string-intp'),
+ (r'\\\\', String.Regex),
+ (r'\\/', String.Regex),
+ (r'[\\#]', String.Regex),
+ (r'[^\\/#]+', String.Regex),
+ (r'/[imsx]*', String.Regex, '#pop'),
+ ],
+ 'end-part': [
+ (r'.+', Comment.Preproc, '#pop')
+ ],
+ 'in-macro-control': [
+ (r'\{%', String.Interpol, '#push'),
+ (r'%\}', String.Interpol, '#pop'),
+ (r'for\b|in\b', Keyword),
+ include('root'),
+ ],
+ 'in-macro-expr': [
+ (r'\{\{', String.Interpol, '#push'),
+ (r'\}\}', String.Interpol, '#pop'),
+ include('root'),
+ ],
+ 'in-attr': [
+ (r'\[', Operator, '#push'),
+ (r'\]', Operator, '#pop'),
+ include('root'),
+ ],
+ }
+ tokens.update(gen_crystalstrings_rules())
diff --git a/pygments/lexers/dsls.py b/pygments/lexers/dsls.py
index 6032017f..57f432a9 100644
--- a/pygments/lexers/dsls.py
+++ b/pygments/lexers/dsls.py
@@ -11,14 +11,14 @@
import re
-from pygments.lexer import RegexLexer, bygroups, words, include, default, \
- this, using, combined
+from pygments.lexer import ExtendedRegexLexer, RegexLexer, bygroups, words, \
+ include, default, this, using, combined
from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
Number, Punctuation, Literal, Whitespace
__all__ = ['ProtoBufLexer', 'BroLexer', 'PuppetLexer', 'RslLexer',
'MscgenLexer', 'VGLLexer', 'AlloyLexer', 'PanLexer',
- 'CrmshLexer', 'ThriftLexer', 'FlatlineLexer']
+ 'CrmshLexer', 'ThriftLexer', 'FlatlineLexer', 'SnowballLexer']
class ProtoBufLexer(RegexLexer):
@@ -767,3 +767,112 @@ class FlatlineLexer(RegexLexer):
(r'(\(|\))', Punctuation),
],
}
+
+
+class SnowballLexer(ExtendedRegexLexer):
+ """
+ Lexer for `Snowball <http://snowballstem.org/>`_ source code.
+
+ .. versionadded:: 2.2
+ """
+
+ name = 'Snowball'
+ aliases = ['snowball']
+ filenames = ['*.sbl']
+
+ _ws = r'\n\r\t '
+
+ def __init__(self, **options):
+ self._reset_stringescapes()
+ ExtendedRegexLexer.__init__(self, **options)
+
+ def _reset_stringescapes(self):
+ self._start = "'"
+ self._end = "'"
+
+ def _string(do_string_first):
+ def callback(lexer, match, ctx):
+ s = match.start()
+ text = match.group()
+ string = re.compile(r'([^%s]*)(.)' % re.escape(lexer._start)).match
+ escape = re.compile(r'([^%s]*)(.)' % re.escape(lexer._end)).match
+ pos = 0
+ do_string = do_string_first
+ while pos < len(text):
+ if do_string:
+ match = string(text, pos)
+ yield s + match.start(1), String.Single, match.group(1)
+ if match.group(2) == "'":
+ yield s + match.start(2), String.Single, match.group(2)
+ ctx.stack.pop()
+ break
+ yield s + match.start(2), String.Escape, match.group(2)
+ pos = match.end()
+ match = escape(text, pos)
+ yield s + match.start(), String.Escape, match.group()
+ if match.group(2) != lexer._end:
+ ctx.stack[-1] = 'escape'
+ break
+ pos = match.end()
+ do_string = True
+ ctx.pos = s + match.end()
+ return callback
+
+ def _stringescapes(lexer, match, ctx):
+ lexer._start = match.group(3)
+ lexer._end = match.group(5)
+ return bygroups(Keyword.Reserved, Text, String.Escape, Text,
+ String.Escape)(lexer, match, ctx)
+
+ tokens = {
+ 'root': [
+ (words(('len', 'lenof'), suffix=r'\b'), Operator.Word),
+ include('root1'),
+ ],
+ 'root1': [
+ (r'[%s]+' % _ws, Text),
+ (r'\d+', Number.Integer),
+ (r"'", String.Single, 'string'),
+ (r'[()]', Punctuation),
+ (r'/\*[\w\W]*?\*/', Comment.Multiline),
+ (r'//.*', Comment.Single),
+ (r'[!*+\-/<=>]=|[-=]>|<[+-]|[$*+\-/<=>?\[\]]', Operator),
+ (words(('as', 'get', 'hex', 'among', 'define', 'decimal',
+ 'backwardmode'), suffix=r'\b'),
+ Keyword.Reserved),
+ (words(('strings', 'booleans', 'integers', 'routines', 'externals',
+ 'groupings'), suffix=r'\b'),
+ Keyword.Reserved, 'declaration'),
+ (words(('do', 'or', 'and', 'for', 'hop', 'non', 'not', 'set', 'try',
+ 'fail', 'goto', 'loop', 'next', 'test', 'true',
+ 'false', 'unset', 'atmark', 'attach', 'delete', 'gopast',
+ 'insert', 'repeat', 'sizeof', 'tomark', 'atleast',
+ 'atlimit', 'reverse', 'setmark', 'tolimit', 'setlimit',
+ 'backwards', 'substring'), suffix=r'\b'),
+ Operator.Word),
+ (words(('size', 'limit', 'cursor', 'maxint', 'minint'),
+ suffix=r'\b'),
+ Name.Builtin),
+ (r'(stringdef\b)([%s]*)([^%s]+)' % (_ws, _ws),
+ bygroups(Keyword.Reserved, Text, String.Escape)),
+ (r'(stringescapes\b)([%s]*)(.)([%s]*)(.)' % (_ws, _ws),
+ _stringescapes),
+ (r'[A-Za-z]\w*', Name),
+ ],
+ 'declaration': [
+ (r'\)', Punctuation, '#pop'),
+ (words(('len', 'lenof'), suffix=r'\b'), Name,
+ ('root1', 'declaration')),
+ include('root1'),
+ ],
+ 'string': [
+ (r"[^']*'", _string(True)),
+ ],
+ 'escape': [
+ (r"[^']*'", _string(False)),
+ ],
+ }
+
+ def get_tokens_unprocessed(self, text=None, context=None):
+ self._reset_stringescapes()
+ return ExtendedRegexLexer.get_tokens_unprocessed(self, text, context)
diff --git a/pygments/lexers/esoteric.py b/pygments/lexers/esoteric.py
index c9db26b5..150d930f 100644
--- a/pygments/lexers/esoteric.py
+++ b/pygments/lexers/esoteric.py
@@ -13,7 +13,8 @@ from pygments.lexer import RegexLexer, include, words
from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
Number, Punctuation, Error
-__all__ = ['BrainfuckLexer', 'BefungeLexer', 'RedcodeLexer', 'CAmkESLexer']
+__all__ = ['BrainfuckLexer', 'BefungeLexer', 'RedcodeLexer', 'CAmkESLexer',
+ 'CapDLLexer', 'AheuiLexer']
class BrainfuckLexer(RegexLexer):
@@ -143,6 +144,63 @@ class CAmkESLexer(RegexLexer):
}
+class CapDLLexer(RegexLexer):
+ """
+ Basic lexer for
+ `CapDL <https://ssrg.nicta.com.au/publications/nictaabstracts/Kuz_KLW_10.abstract.pml>`_.
+
+ The source of the primary tool that reads such specifications is available
+ at https://github.com/seL4/capdl/tree/master/capDL-tool. Note that this
+ lexer only supports a subset of the grammar. For example, identifiers can
+ shadow type names, but these instances are currently incorrectly
+ highlighted as types. Supporting this would need a stateful lexer that is
+ considered unnecessarily complex for now.
+ """
+ name = 'CapDL'
+ aliases = ['capdl']
+ filenames = ['*.cdl']
+
+ tokens = {
+ 'root':[
+
+ # C pre-processor directive
+ (r'^\s*#.*\n', Comment.Preproc),
+
+ # Whitespace, comments
+ (r'\s+', Text),
+ (r'/\*(.|\n)*?\*/', Comment),
+ (r'(//|--).*\n', Comment),
+
+ (r'[<>\[\(\)\{\},:;=\]]', Punctuation),
+ (r'\.\.', Punctuation),
+
+ (words(('arch', 'arm11', 'caps', 'child_of', 'ia32', 'irq', 'maps',
+ 'objects'), suffix=r'\b'), Keyword),
+
+ (words(('aep', 'asid_pool', 'cnode', 'ep', 'frame', 'io_device',
+ 'io_ports', 'io_pt', 'notification', 'pd', 'pt', 'tcb',
+ 'ut', 'vcpu'), suffix=r'\b'), Keyword.Type),
+
+ # Properties
+ (words(('asid', 'addr', 'badge', 'cached', 'dom', 'domainID', 'elf',
+ 'fault_ep', 'G', 'guard', 'guard_size', 'init', 'ip',
+ 'prio', 'sp', 'R', 'RG', 'RX', 'RW', 'RWG', 'RWX', 'W',
+ 'WG', 'WX', 'level', 'masked', 'master_reply', 'paddr',
+ 'ports', 'reply', 'uncached'), suffix=r'\b'),
+ Keyword.Reserved),
+
+ # Literals
+ (r'0[xX][\da-fA-F]+', Number.Hex),
+ (r'\d+(\.\d+)?(k|M)?', Number),
+ (words(('bits',), suffix=r'\b'), Number),
+ (words(('cspace', 'vspace', 'reply_slot', 'caller_slot',
+ 'ipc_buffer_slot'), suffix=r'\b'), Number),
+
+ # Identifiers
+ (r'[a-zA-Z_][-_@\.\w]*', Name),
+ ],
+ }
+
class RedcodeLexer(RegexLexer):
"""
A simple Redcode lexer based on ICWS'94.
@@ -177,3 +235,41 @@ class RedcodeLexer(RegexLexer):
(r'[-+]?\d+', Number.Integer),
],
}
+
+
+class AheuiLexer(RegexLexer):
+ """
+ Aheui_ Lexer.
+
+ Aheui_ is esoteric language based on Korean alphabets.
+
+ .. _Aheui:: http://aheui.github.io/
+
+ """
+
+ name = 'Aheui'
+ aliases = ['aheui']
+ filenames = ['*.aheui']
+
+ tokens = {
+ 'root': [
+ (u'['
+ u'나-낳냐-냫너-넣녀-녛노-놓뇨-눟뉴-닇'
+ u'다-닿댜-댷더-덯뎌-뎧도-돟됴-둫듀-딓'
+ u'따-땋땨-떃떠-떻뗘-뗳또-똫뚀-뚷뜌-띟'
+ u'라-랗랴-럏러-렇려-렿로-롷료-뤃류-릫'
+ u'마-맣먀-먛머-멓며-몋모-뫃묘-뭏뮤-믷'
+ u'바-밯뱌-뱧버-벟벼-볗보-봏뵤-붛뷰-빃'
+ u'빠-빻뺘-뺳뻐-뻫뼈-뼣뽀-뽛뾰-뿧쀼-삏'
+ u'사-샇샤-샿서-섷셔-셯소-솧쇼-숳슈-싛'
+ u'싸-쌓쌰-썋써-쎃쎠-쎻쏘-쏳쑈-쑿쓔-씧'
+ u'자-잫쟈-쟣저-젛져-졓조-좋죠-줗쥬-즿'
+ u'차-챃챠-챻처-첳쳐-쳫초-촣쵸-춯츄-칗'
+ u'카-캏캬-컇커-컿켜-켷코-콯쿄-쿻큐-킣'
+ u'타-탛탸-턓터-텋텨-톃토-톻툐-퉇튜-틯'
+ u'파-팧퍄-퍟퍼-펗펴-폏포-퐇표-풓퓨-픻'
+ u'하-핳햐-햫허-헣혀-혛호-홓효-훟휴-힇'
+ u']', Operator),
+ ('.', Comment),
+ ],
+ }
diff --git a/pygments/lexers/javascript.py b/pygments/lexers/javascript.py
index 5dca6832..d8ce87d4 100644
--- a/pygments/lexers/javascript.py
+++ b/pygments/lexers/javascript.py
@@ -20,7 +20,7 @@ import pygments.unistring as uni
__all__ = ['JavascriptLexer', 'KalLexer', 'LiveScriptLexer', 'DartLexer',
'TypeScriptLexer', 'LassoLexer', 'ObjectiveJLexer',
- 'CoffeeScriptLexer', 'MaskLexer', 'EarlGreyLexer']
+ 'CoffeeScriptLexer', 'MaskLexer', 'EarlGreyLexer', 'JuttleLexer']
JS_IDENT_START = ('(?:[$_' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl') +
']|\\\\u[a-fA-F0-9]{4})')
@@ -1438,3 +1438,63 @@ class EarlGreyLexer(RegexLexer):
(r'\d+', Number.Integer)
],
}
+
+class JuttleLexer(RegexLexer):
+ """
+ For `Juttle`_ source code.
+
+ .. _Juttle: https://github.com/juttle/juttle
+
+ """
+
+ name = 'Juttle'
+ aliases = ['juttle', 'juttle']
+ filenames = ['*.juttle']
+ mimetypes = ['application/juttle', 'application/x-juttle',
+ 'text/x-juttle', 'text/juttle']
+
+ flags = re.DOTALL | re.UNICODE | re.MULTILINE
+
+ tokens = {
+ 'commentsandwhitespace': [
+ (r'\s+', Text),
+ (r'//.*?\n', Comment.Single),
+ (r'/\*.*?\*/', Comment.Multiline)
+ ],
+ 'slashstartsregex': [
+ include('commentsandwhitespace'),
+ (r'/(\\.|[^[/\\\n]|\[(\\.|[^\]\\\n])*])+/'
+ r'([gim]+\b|\B)', String.Regex, '#pop'),
+ (r'(?=/)', Text, ('#pop', 'badregex')),
+ default('#pop')
+ ],
+ 'badregex': [
+ (r'\n', Text, '#pop')
+ ],
+ 'root': [
+ (r'^(?=\s|/)', Text, 'slashstartsregex'),
+ include('commentsandwhitespace'),
+ (r':\d{2}:\d{2}:\d{2}(\.\d*)?:', String.Moment),
+ (r':(now|beginning|end|forever|yesterday|today|tomorrow|(\d+(\.\d*)?|\.\d+)(ms|[smhdwMy])?):', String.Moment),
+ (r':\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d*)?)?(Z|[+-]\d{2}:\d{2}|[+-]\d{4})?:', String.Moment),
+ (r':((\d+(\.\d*)?|\.\d+)[ ]+)?(millisecond|second|minute|hour|day|week|month|year)[s]?'
+ r'(([ ]+and[ ]+(\d+[ ]+)?(millisecond|second|minute|hour|day|week|month|year)[s]?)'
+ r'|[ ]+(ago|from[ ]+now))*:', String.Moment),
+ (r'\+\+|--|~|&&|\?|:|\|\||\\(?=\n)|'
+ r'(==?|!=?|[-<>+*%&|^/])=?', Operator, 'slashstartsregex'),
+ (r'[{(\[;,]', Punctuation, 'slashstartsregex'),
+ (r'[})\].]', Punctuation),
+ (r'(import|return|continue|if|else)\b', Keyword, 'slashstartsregex'),
+ (r'(var|const|function|reducer|sub|input)\b', Keyword.Declaration, 'slashstartsregex'),
+ (r'(batch|emit|filter|head|join|keep|pace|pass|put|read|reduce|remove|'
+ r'sequence|skip|sort|split|tail|unbatch|uniq|view|write)\b', Keyword.Reserved),
+ (r'(true|false|null|Infinity)\b', Keyword.Constant),
+ (r'(Array|Date|Juttle|Math|Number|Object|RegExp|String)\b', Name.Builtin),
+ (JS_IDENT, Name.Other),
+ (r'[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?', Number.Float),
+ (r'[0-9]+', Number.Integer),
+ (r'"(\\\\|\\"|[^"])*"', String.Double),
+ (r"'(\\\\|\\'|[^'])*'", String.Single)
+ ]
+
+ }
diff --git a/pygments/lexers/make.py b/pygments/lexers/make.py
index 7ad616dd..9b6273d7 100644
--- a/pygments/lexers/make.py
+++ b/pygments/lexers/make.py
@@ -90,7 +90,7 @@ class BaseMakefileLexer(RegexLexer):
bygroups(Keyword, Text), 'export'),
(r'export\s+', Keyword),
# assignment
- (r'([\w${}.-]+)(\s*)([!?:+]?=)([ \t]*)((?:.*\\\n)+|.*\n)',
+ (r'([\w${}().-]+)(\s*)([!?:+]?=)([ \t]*)((?:.*\\\n)+|.*\n)',
bygroups(Name.Variable, Text, Operator, Text, using(BashLexer))),
# strings
(r'(?s)"(\\\\|\\.|[^"\\])*"', String.Double),
diff --git a/pygments/lexers/other.py b/pygments/lexers/other.py
index afd0fda5..dd45083c 100644
--- a/pygments/lexers/other.py
+++ b/pygments/lexers/other.py
@@ -36,5 +36,6 @@ from pygments.lexers.urbi import UrbiscriptLexer
from pygments.lexers.smalltalk import SmalltalkLexer, NewspeakLexer
from pygments.lexers.installers import NSISLexer, RPMSpecLexer
from pygments.lexers.textedit import AwkLexer
+from pygments.lexers.smv import NuSMVLexer
__all__ = []
diff --git a/pygments/lexers/rust.py b/pygments/lexers/rust.py
index 5d1162b8..d3d98ee8 100644
--- a/pygments/lexers/rust.py
+++ b/pygments/lexers/rust.py
@@ -18,7 +18,7 @@ __all__ = ['RustLexer']
class RustLexer(RegexLexer):
"""
- Lexer for the Rust programming language (version 1.0).
+ Lexer for the Rust programming language (version 1.10).
.. versionadded:: 1.6
"""
@@ -49,17 +49,21 @@ class RustLexer(RegexLexer):
(r"""\$([a-zA-Z_]\w*|\(,?|\),?|,?)""", Comment.Preproc),
# Keywords
(words((
- 'as', 'box', 'crate', 'do', 'else', 'enum', 'extern', # break and continue are in labels
- 'fn', 'for', 'if', 'impl', 'in', 'loop', 'match', 'mut', 'priv',
- 'proc', 'pub', 'ref', 'return', 'static', 'struct',
- 'trait', 'true', 'type', 'unsafe', 'while'), suffix=r'\b'),
+ 'as', 'box', 'const', 'crate', 'else', 'extern',
+ 'for', 'if', 'impl', 'in', 'loop', 'match', 'move',
+ 'mut', 'pub', 'ref', 'return', 'static', 'super',
+ 'trait', 'unsafe', 'use', 'where', 'while'), suffix=r'\b'),
Keyword),
- (words(('alignof', 'be', 'const', 'offsetof', 'pure', 'sizeof',
- 'typeof', 'once', 'unsized', 'yield'), suffix=r'\b'),
+ (words(('abstract', 'alignof', 'become', 'do', 'final', 'macro',
+ 'offsetof', 'override', 'priv', 'proc', 'pure', 'sizeof',
+ 'typeof', 'unsized', 'virtual', 'yield'), suffix=r'\b'),
Keyword.Reserved),
- (r'(mod|use)\b', Keyword.Namespace),
(r'(true|false)\b', Keyword.Constant),
+ (r'mod\b', Keyword, 'modname'),
(r'let\b', Keyword.Declaration),
+ (r'fn\b', Keyword, 'funcname'),
+ (r'(struct|enum|type|union)\b', Keyword, 'typename'),
+ (r'(default)(\s+)(type|fn)\b', bygroups(Keyword, Text, Keyword)),
(words(('u8', 'u16', 'u32', 'u64', 'i8', 'i16', 'i32', 'i64', 'usize',
'isize', 'f32', 'f64', 'str', 'bool'), suffix=r'\b'),
Keyword.Type),
@@ -88,11 +92,11 @@ class RustLexer(RegexLexer):
'Ok', 'Err',
'SliceConcatExt',
'String', 'ToString',
- 'Vec',
- ), suffix=r'\b'),
+ 'Vec'), suffix=r'\b'),
Name.Builtin),
# Labels
- (r'(break|continue)(\s*)(\'[A-Za-z_]\w*)?', bygroups(Keyword, Text.Whitespace, Name.Label)),
+ (r'(break|continue)(\s*)(\'[A-Za-z_]\w*)?',
+ bygroups(Keyword, Text.Whitespace, Name.Label)),
# Character Literal
(r"""'(\\['"\\nrt]|\\x[0-7][0-9a-fA-F]|\\0"""
r"""|\\u\{[0-9a-fA-F]{1,6}\}|.)'""",
@@ -148,6 +152,21 @@ class RustLexer(RegexLexer):
(r'\*/', String.Doc, '#pop'),
(r'[*/]', String.Doc),
],
+ 'modname': [
+ (r'\s+', Text),
+ (r'[a-zA-Z_]\w*', Name.Namespace, '#pop'),
+ default('#pop'),
+ ],
+ 'funcname': [
+ (r'\s+', Text),
+ (r'[a-zA-Z_]\w*', Name.Function, '#pop'),
+ default('#pop'),
+ ],
+ 'typename': [
+ (r'\s+', Text),
+ (r'[a-zA-Z_]\w*', Name.Class, '#pop'),
+ default('#pop'),
+ ],
'number_lit': [
(r'[ui](8|16|32|64|size)', Keyword, '#pop'),
(r'f(32|64)', Keyword, '#pop'),
diff --git a/pygments/lexers/scripting.py b/pygments/lexers/scripting.py
index ac0f7533..5849161b 100644
--- a/pygments/lexers/scripting.py
+++ b/pygments/lexers/scripting.py
@@ -50,36 +50,47 @@ class LuaLexer(RegexLexer):
filenames = ['*.lua', '*.wlua']
mimetypes = ['text/x-lua', 'application/x-lua']
+ _comment_multiline = r'(?:--\[(?P<level>=*)\[[\w\W]*?\](?P=level)\])'
+ _comment_single = r'(?:--.*$)'
+ _space = r'(?:\s+)'
+ _s = r'(?:%s|%s|%s)' % (_comment_multiline, _comment_single, _space)
+ _name = r'(?:[^\W\d]\w*)'
+
tokens = {
'root': [
- # lua allows a file to start with a shebang
- (r'#!(.*?)$', Comment.Preproc),
+ # Lua allows a file to start with a shebang.
+ (r'#!.*', Comment.Preproc),
default('base'),
],
+ 'ws': [
+ (_comment_multiline, Comment.Multiline),
+ (_comment_single, Comment.Single),
+ (_space, Text),
+ ],
'base': [
- (r'(?s)--\[(=*)\[.*?\]\1\]', Comment.Multiline),
- ('--.*$', Comment.Single),
+ include('ws'),
+ (r'(?i)0x[\da-f]*(\.[\da-f]*)?(p[+-]?\d+)?', Number.Hex),
(r'(?i)(\d*\.\d+|\d+\.\d*)(e[+-]?\d+)?', Number.Float),
(r'(?i)\d+e[+-]?\d+', Number.Float),
- ('(?i)0x[0-9a-f]*', Number.Hex),
(r'\d+', Number.Integer),
- (r'\n', Text),
- (r'[^\S\n]', Text),
# multiline strings
(r'(?s)\[(=*)\[.*?\]\1\]', String),
- (r'(==|~=|<=|>=|\.\.\.|\.\.|[=+\-*/%^<>#])', Operator),
+ (r'::', Punctuation, 'label'),
+ (r'\.{3}', Punctuation),
+ (r'[=<>|~&+\-*/%#^]+|\.\.', Operator),
(r'[\[\]{}().,:;]', Punctuation),
(r'(and|or|not)\b', Operator.Word),
('(break|do|else|elseif|end|for|if|in|repeat|return|then|until|'
- r'while)\b', Keyword),
+ r'while)\b', Keyword.Reserved),
+ (r'goto\b', Keyword.Reserved, 'goto'),
(r'(local)\b', Keyword.Declaration),
(r'(true|false|nil)\b', Keyword.Constant),
- (r'(function)\b', Keyword, 'funcname'),
+ (r'(function)\b', Keyword.Reserved, 'funcname'),
(r'[A-Za-z_]\w*(\.[A-Za-z_]\w*)?', Name),
@@ -88,31 +99,38 @@ class LuaLexer(RegexLexer):
],
'funcname': [
- (r'\s+', Text),
- ('(?:([A-Za-z_]\w*)(\.))?([A-Za-z_]\w*)',
- bygroups(Name.Class, Punctuation, Name.Function), '#pop'),
+ include('ws'),
+ (r'[.:]', Punctuation),
+ (r'%s(?=%s*[.:])' % (_name, _s), Name.Class),
+ (_name, Name.Function, '#pop'),
# inline function
('\(', Punctuation, '#pop'),
],
- # if I understand correctly, every character is valid in a lua string,
- # so this state is only for later corrections
- 'string': [
- ('.', String)
+ 'goto': [
+ include('ws'),
+ (_name, Name.Label, '#pop'),
+ ],
+
+ 'label': [
+ include('ws'),
+ (r'::', Punctuation, '#pop'),
+ (_name, Name.Label),
],
'stringescape': [
- (r'''\\([abfnrtv\\"']|\d{1,3})''', String.Escape)
+ (r'\\([abfnrtv\\"\']|[\r\n]{1,2}|z\s*|x[0-9a-fA-F]{2}|\d{1,3}|'
+ r'u\{[0-9a-fA-F]+\})', String.Escape),
],
'sqs': [
- ("'", String, '#pop'),
- include('string')
+ (r"'", String.Single, '#pop'),
+ (r"[^\\']+", String.Single),
],
'dqs': [
- ('"', String, '#pop'),
- include('string')
+ (r'"', String.Double, '#pop'),
+ (r'[^\\"]+', String.Double),
]
}
diff --git a/pygments/lexers/shell.py b/pygments/lexers/shell.py
index ad2e2d7a..c2f54fc2 100644
--- a/pygments/lexers/shell.py
+++ b/pygments/lexers/shell.py
@@ -452,9 +452,9 @@ class BatchLexer(RegexLexer):
bygroups(String.Double, using(this, state='string'), Text,
Punctuation)),
(r'"', String.Double, ('#pop', 'for2', 'string')),
- (r"('(?:%s|[\w\W])*?')([%s%s]*)(\))" % (_variable, _nl, _ws),
+ (r"('(?:%%%%|%s|[\w\W])*?')([%s%s]*)(\))" % (_variable, _nl, _ws),
bygroups(using(this, state='sqstring'), Text, Punctuation)),
- (r'(`(?:%s|[\w\W])*?`)([%s%s]*)(\))' % (_variable, _nl, _ws),
+ (r'(`(?:%%%%|%s|[\w\W])*?`)([%s%s]*)(\))' % (_variable, _nl, _ws),
bygroups(using(this, state='bqstring'), Text, Punctuation)),
include('for2')
],
diff --git a/pygments/lexers/smv.py b/pygments/lexers/smv.py
new file mode 100644
index 00000000..15fc9381
--- /dev/null
+++ b/pygments/lexers/smv.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+"""
+ pygments.lexers.smv
+ ~~~~~~~~~~~~~~~~~~~
+
+ Lexers for the SMV languages.
+
+ :copyright: Copyright 2006-2015 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from pygments.lexer import RegexLexer, words
+from pygments.token import Comment, Generic, Keyword, Name, Number, \
+ Operator, Punctuation, Text
+
+__all__ = ['NuSMVLexer']
+
+
+class NuSMVLexer(RegexLexer):
+ """
+ Lexer for the NuSMV language.
+ """
+
+ name = 'NuSMV'
+ aliases = ['nusmv']
+ filenames = ['*.smv']
+ mimetypes = []
+
+ tokens = {
+ 'root': [
+ # Comments
+ (r'(?s)\/\-\-.*?\-\-/', Comment),
+ (r'--.*\n', Comment),
+
+ # Reserved
+ (words(('MODULE','DEFINE','MDEFINE','CONSTANTS','VAR','IVAR',
+ 'FROZENVAR','INIT','TRANS','INVAR','SPEC','CTLSPEC','LTLSPEC',
+ 'PSLSPEC','COMPUTE','NAME','INVARSPEC','FAIRNESS','JUSTICE',
+ 'COMPASSION','ISA','ASSIGN','CONSTRAINT','SIMPWFF','CTLWFF',
+ 'LTLWFF','PSLWFF','COMPWFF','IN','MIN','MAX','MIRROR','PRED',
+ 'PREDICATES'), suffix=r'(?![\w$#-])'), Keyword.Declaration),
+ (r'process(?![\w$#-])', Keyword),
+ (words(('array','of','boolean','integer','real','word'),
+ suffix=r'(?![\w$#-])'), Keyword.Type),
+ (words(('case','esac'), suffix=r'(?![\w$#-])'), Keyword),
+ (words(('word1','bool','signed','unsigned','extend','resize',
+ 'sizeof','uwconst','swconst','init','self','count','abs','max',
+ 'min'), suffix=r'(?![\w$#-])'), Name.Builtin),
+ (words(('EX','AX','EF','AF','EG','AG','E','F','O','G','H','X','Y',
+ 'Z','A','U','S','V','T','BU','EBF','ABF','EBG','ABG','next',
+ 'mod','union','in','xor','xnor'), suffix=r'(?![\w$#-])'),
+ Operator.Word),
+ (words(('TRUE','FALSE'), suffix=r'(?![\w$#-])'), Keyword.Constant),
+
+ # Names
+ (r'[a-zA-Z_][\w$#-]*', Name.Variable),
+
+ # Operators
+ (r':=', Operator),
+ (r'[&\|\+\-\*/<>!=]', Operator),
+
+ # Literals
+ (r'\-?\d+\b', Number.Integer),
+ (r'0[su][bB]\d*_[01_]+', Number.Bin),
+ (r'0[su][oO]\d*_[01234567_]+', Number.Oct),
+ (r'0[su][dD]\d*_[\d_]+', Number.Dec),
+ (r'0[su][hH]\d*_[\da-fA-F_]+', Number.Hex),
+
+ # Whitespace, punctuation and the rest
+ (r'\s+', Text.Whitespace),
+ (r'[\(\)\[\]\{\};\?:\.,]', Punctuation),
+ (r'.', Generic.Error),
+ ]
+ }
+
diff --git a/pygments/lexers/sql.py b/pygments/lexers/sql.py
index 7c06226b..e225a66e 100644
--- a/pygments/lexers/sql.py
+++ b/pygments/lexers/sql.py
@@ -41,17 +41,19 @@
import re
from pygments.lexer import Lexer, RegexLexer, do_insertions, bygroups, words
-from pygments.token import Punctuation, \
+from pygments.token import Punctuation, Whitespace, Error, \
Text, Comment, Operator, Keyword, Name, String, Number, Generic
from pygments.lexers import get_lexer_by_name, ClassNotFound
from pygments.util import iteritems
from pygments.lexers._postgres_builtins import KEYWORDS, DATATYPES, \
PSEUDO_TYPES, PLPGSQL_KEYWORDS
+from pygments.lexers import _tsql_builtins
__all__ = ['PostgresLexer', 'PlPgsqlLexer', 'PostgresConsoleLexer',
- 'SqlLexer', 'MySqlLexer', 'SqliteConsoleLexer', 'RqlLexer']
+ 'SqlLexer', 'TransactSqlLexer', 'MySqlLexer',
+ 'SqliteConsoleLexer', 'RqlLexer']
line_re = re.compile('.*?\n')
@@ -151,7 +153,7 @@ class PostgresLexer(PostgresBase, RegexLexer):
tokens = {
'root': [
(r'\s+', Text),
- (r'--.*?\n', Comment.Single),
+ (r'--.*\n?', Comment.Single),
(r'/\*', Comment.Multiline, 'multiline-comments'),
(r'(' + '|'.join(s.replace(" ", "\s+")
for s in DATATYPES + PSEUDO_TYPES)
@@ -378,7 +380,7 @@ class SqlLexer(RegexLexer):
tokens = {
'root': [
(r'\s+', Text),
- (r'--.*?\n', Comment.Single),
+ (r'--.*\n?', Comment.Single),
(r'/\*', Comment.Multiline, 'multiline-comments'),
(words((
'ABORT', 'ABS', 'ABSOLUTE', 'ACCESS', 'ADA', 'ADD', 'ADMIN', 'AFTER', 'AGGREGATE',
@@ -479,6 +481,62 @@ class SqlLexer(RegexLexer):
}
+class TransactSqlLexer(RegexLexer):
+ """
+ Transact-SQL (T-SQL) is Microsoft's and Sybase's proprietary extension to
+ SQL.
+
+ The list of keywords includes ODBC and keywords reserved for future use..
+ """
+
+ name = 'Transact-SQL'
+ aliases = ['tsql', 't-sql']
+ filenames = ['*.sql']
+ mimetypes = ['text/x-tsql']
+
+ # Use re.UNICODE to allow non ASCII letters in names.
+ flags = re.IGNORECASE | re.UNICODE
+ tokens = {
+ 'root': [
+ (r'\s+', Whitespace),
+ (r'--(?m).*?$\n?', Comment.Single),
+ (r'/\*', Comment.Multiline, 'multiline-comments'),
+ (words(_tsql_builtins.OPERATORS), Operator),
+ (words(_tsql_builtins.OPERATOR_WORDS, suffix=r'\b'), Operator.Word),
+ (words(_tsql_builtins.TYPES, suffix=r'\b'), Name.Class),
+ (words(_tsql_builtins.FUNCTIONS, suffix=r'\b'), Name.Function),
+ (r'(goto)(\s+)(\w+\b)', bygroups(Keyword, Whitespace, Name.Label)),
+ (words(_tsql_builtins.KEYWORDS, suffix=r'\b'), Keyword),
+ (r'(\[)([^]]+)(\])', bygroups(Operator, Name, Operator)),
+ (r'0x[0-9a-f]+', Number.Hex),
+ # Float variant 1, for example: 1., 1.e2, 1.2e3
+ (r'[0-9]+\.[0-9]*(e[+-]?[0-9]+)?', Number.Float),
+ # Float variant 2, for example: .1, .1e2
+ (r'\.[0-9]+(e[+-]?[0-9]+)?', Number.Float),
+ # Float variant 3, for example: 123e45
+ (r'[0-9]+e[+-]?[0-9]+', Number.Float),
+ (r'[0-9]+', Number.Integer),
+ (r"'(''|[^'])*'", String.Single),
+ (r'"(""|[^"])*"', String.Symbol),
+ (r'[;(),.]', Punctuation),
+ # Below we use \w even for the first "real" character because
+ # tokens starting with a digit have already been recognized
+ # as Number above.
+ (r'@@\w+', Name.Builtin),
+ (r'@\w+', Name.Variable),
+ (r'(\w+)(:)', bygroups(Name.Label, Punctuation)),
+ (r'#?#?\w+', Name), # names for temp tables and anything else
+ (r'\?', Name.Variable.Magic), # parameter for prepared statements
+ ],
+ 'multiline-comments': [
+ (r'/\*', Comment.Multiline, 'multiline-comments'),
+ (r'\*/', Comment.Multiline, '#pop'),
+ (r'[^/*]+', Comment.Multiline),
+ (r'[/*]', Comment.Multiline)
+ ]
+ }
+
+
class MySqlLexer(RegexLexer):
"""
Special lexer for MySQL.
@@ -492,7 +550,7 @@ class MySqlLexer(RegexLexer):
tokens = {
'root': [
(r'\s+', Text),
- (r'(#|--\s+).*?\n', Comment.Single),
+ (r'(#|--\s+).*\n?', Comment.Single),
(r'/\*', Comment.Multiline, 'multiline-comments'),
(r'[0-9]+', Number.Integer),
(r'[0-9]*\.[0-9]+(e[+-][0-9]+)', Number.Float),
diff --git a/pygments/lexers/templates.py b/pygments/lexers/templates.py
index 3e55b6ad..e6eeaa25 100644
--- a/pygments/lexers/templates.py
+++ b/pygments/lexers/templates.py
@@ -44,7 +44,7 @@ __all__ = ['HtmlPhpLexer', 'XmlPhpLexer', 'CssPhpLexer',
'TeaTemplateLexer', 'LassoHtmlLexer', 'LassoXmlLexer',
'LassoCssLexer', 'LassoJavascriptLexer', 'HandlebarsLexer',
'HandlebarsHtmlLexer', 'YamlJinjaLexer', 'LiquidLexer',
- 'TwigLexer', 'TwigHtmlLexer']
+ 'TwigLexer', 'TwigHtmlLexer', 'Angular2Lexer', 'Angular2HtmlLexer']
class ErbLexer(Lexer):
@@ -2174,3 +2174,79 @@ class TwigHtmlLexer(DelegatingLexer):
def __init__(self, **options):
super(TwigHtmlLexer, self).__init__(HtmlLexer, TwigLexer, **options)
+
+
+class Angular2Lexer(RegexLexer):
+ """
+ Generic `angular2 <http://victorsavkin.com/post/119943127151/angular-2-template-syntax>` template lexer.
+
+ Highlights only the Angular template tags (stuff between `{{` and `}}` and
+ special attributes: '(event)=', '[property]=', '[(twoWayBinding)]=').
+ Everything else is left for a delegating lexer.
+
+ .. versionadded:: 2.1a0
+ """
+
+ name = "Angular2"
+ aliases = ['ng2']
+
+ tokens = {
+ 'root': [
+ (r'[^{([*#]+', Other),
+
+ # {{meal.name}}
+ (r'(\{\{)(\s*)', bygroups(Comment.Preproc, Text), 'ngExpression'),
+
+ # (click)="deleteOrder()"; [value]="test"; [(twoWayTest)]="foo.bar"
+ (r'([([]+)([\w:.-]+)([\])]+)(\s*)(=)(\s*)',
+ bygroups(Punctuation, Name.Attribute, Punctuation, Text, Operator, Text), 'attr'),
+ (r'([([]+)([\w:.-]+)([\])]+)(\s*)',
+ bygroups(Punctuation, Name.Attribute, Punctuation, Text)),
+
+ # *ngIf="..."; #f="ngForm"
+ (r'([*#])([\w:.-]+)(\s*)(=)(\s*)',
+ bygroups(Punctuation, Name.Attribute, Punctuation, Operator), 'attr'),
+ (r'([*#])([\w:.-]+)(\s*)',
+ bygroups(Punctuation, Name.Attribute, Punctuation)),
+ ],
+
+ 'ngExpression': [
+ (r'\s+(\|\s+)?', Text),
+ (r'\}\}', Comment.Preproc, '#pop'),
+
+ # Literals
+ (r':?(true|false)', String.Boolean),
+ (r':?"(\\\\|\\"|[^"])*"', String.Double),
+ (r":?'(\\\\|\\'|[^'])*'", String.Single),
+ (r"[0-9](\.[0-9]*)?(eE[+-][0-9])?[flFLdD]?|"
+ r"0[xX][0-9a-fA-F]+[Ll]?", Number),
+
+ # Variabletext
+ (r'[a-zA-Z][\w-]*(\(.*\))?', Name.Variable),
+ (r'\.[\w-]+(\(.*\))?', Name.Variable),
+
+ # inline If
+ (r'(\?)(\s*)([^}\s]+)(\s*)(:)(\s*)([^}\s]+)(\s*)', bygroups(Operator, Text, String, Text, Operator, Text, String, Text)),
+ ],
+ 'attr': [
+ ('".*?"', String, '#pop'),
+ ("'.*?'", String, '#pop'),
+ (r'[^\s>]+', String, '#pop'),
+ ],
+ }
+
+
+class Angular2HtmlLexer(DelegatingLexer):
+ """
+ Subclass of the `Angular2Lexer` that highlights unlexed data with the
+ `HtmlLexer`.
+
+ .. versionadded:: 2.0
+ """
+
+ name = "HTML + Angular2"
+ aliases = ["html+ng2"]
+ filenames = ['*.ng2']
+
+ def __init__(self, **options):
+ super(Angular2HtmlLexer, self).__init__(HtmlLexer, Angular2Lexer, **options) \ No newline at end of file
diff --git a/pygments/lexers/verification.py b/pygments/lexers/verification.py
index 4042d44e..3e77e04a 100644
--- a/pygments/lexers/verification.py
+++ b/pygments/lexers/verification.py
@@ -88,13 +88,14 @@ class SilverLexer(RegexLexer):
'assume', 'goto', 'while', 'if', 'elseif', 'else', 'fresh',
'constraining', 'Seq', 'Set', 'Multiset', 'union', 'intersection',
'setminus', 'subset', 'unfolding', 'in', 'old', 'forall', 'exists',
- 'acc', 'wildcard', 'write', 'none', 'epsilon', 'perm', 'unique'),
+ 'acc', 'wildcard', 'write', 'none', 'epsilon', 'perm', 'unique',
+ 'apply', 'package', 'folding', 'label'),
suffix=r'\b'), Keyword),
(words(('Int', 'Perm', 'Bool', 'Ref'), suffix=r'\b'), Keyword.Type),
include('numbers'),
- (r'[!%&*+=|?:<>/-]', Operator),
- (r"([{}():;,.])", Punctuation),
+ (r'[!%&*+=|?:<>/\-\[\]]', Operator),
+ (r'([{}():;,.])', Punctuation),
# Identifier
(r'[\w$]\w*', Name),
],
diff --git a/pygments/lexers/whiley.py b/pygments/lexers/whiley.py
new file mode 100644
index 00000000..0795a030
--- /dev/null
+++ b/pygments/lexers/whiley.py
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+"""
+ pygments.lexers.whiley
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+ Lexers for the Whiley language.
+
+ :copyright: Copyright 2006-2016 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from pygments.lexer import RegexLexer, bygroups, words
+from pygments.token import Comment, Keyword, Name, Number, Operator, \
+ Punctuation, String, Text
+
+__all__ = ['WhileyLexer']
+
+
+class WhileyLexer(RegexLexer):
+ """
+ Lexer for the Whiley programming language.
+ """
+ name = 'Whiley'
+ filenames = ['*.whiley']
+ aliases = ['whiley']
+ mimetypes = ['text/x-whiley']
+
+ # See the language specification:
+ # http://whiley.org/download/WhileyLanguageSpec.pdf
+
+ tokens = {
+ 'root': [
+ # Whitespace
+ (r'\s+', Text),
+
+ # Comments
+ (r'//.*', Comment.Single),
+ # don't parse empty comment as doc comment
+ (r'/\*\*/', Comment.Multiline),
+ (r'(?s)/\*\*.*?\*/', String.Doc),
+ (r'(?s)/\*.*?\*/', Comment.Multiline),
+
+ # Keywords
+ (words((
+ 'if', 'else', 'while', 'for', 'do', 'return',
+ 'switch', 'case', 'default', 'break', 'continue',
+ 'requires', 'ensures', 'where', 'assert', 'assume',
+ 'all', 'no', 'some', 'in', 'is', 'new',
+ 'throw', 'try', 'catch', 'debug', 'skip', 'fail',
+ 'finite', 'total',
+ ), suffix=r'\b'), Keyword.Reserved),
+ (words((
+ 'function', 'method', 'public', 'private', 'protected',
+ 'export', 'native',
+ ), suffix=r'\b'), Keyword.Declaration),
+ # "constant" & "type" are not keywords unless used in declarations
+ (r'(constant|type)(\s+)([a-zA-Z_]\w*)(\s+)(is)\b',
+ bygroups(Keyword.Declaration, Text, Name, Text, Keyword.Reserved)),
+ (r'(true|false|null)\b', Keyword.Constant),
+ (r'(bool|byte|int|real|any|void)\b', Keyword.Type),
+ # "from" is not a keyword unless used with import
+ (r'(import)(\s+)(\*)([^\S\n]+)(from)\b',
+ bygroups(Keyword.Namespace, Text, Punctuation, Text, Keyword.Namespace)),
+ (r'(import)(\s+)([a-zA-Z_]\w*)([^\S\n]+)(from)\b',
+ bygroups(Keyword.Namespace, Text, Name, Text, Keyword.Namespace)),
+ (r'(package|import)\b', Keyword.Namespace),
+
+ # standard library: https://github.com/Whiley/WhileyLibs/
+ (words((
+ # types defined in whiley.lang.Int
+ 'i8', 'i16', 'i32', 'i64',
+ 'u8', 'u16', 'u32', 'u64',
+ 'uint', 'nat',
+
+ # whiley.lang.Any
+ 'toString',
+ ), suffix=r'\b'), Name.Builtin),
+
+ # byte literal
+ (r'[01]+b', Number.Bin),
+
+ # decimal literal
+ (r'[0-9]+\.[0-9]+', Number.Float),
+ # match "1." but not ranges like "3..5"
+ (r'[0-9]+\.(?!\.)', Number.Float),
+
+ # integer literal
+ (r'0x[0-9a-fA-F]+', Number.Hex),
+ (r'[0-9]+', Number.Integer),
+
+ # character literal
+ (r"""'[^\\]'""", String.Char),
+ (r"""(')(\\['"\\btnfr])(')""",
+ bygroups(String.Char, String.Escape, String.Char)),
+
+ # string literal
+ (r'"', String, 'string'),
+
+ # operators and punctuation
+ (r'[{}()\[\],.;]', Punctuation),
+ (u'[+\\-*/%&|<>^!~@=:?'
+ # unicode operators
+ u'\u2200\u2203\u2205\u2282\u2286\u2283\u2287'
+ u'\u222A\u2229\u2264\u2265\u2208\u2227\u2228'
+ u']', Operator),
+
+ # identifier
+ (r'[a-zA-Z_]\w*', Name),
+ ],
+ 'string': [
+ (r'"', String, '#pop'),
+ (r'\\[btnfr]', String.Escape),
+ (r'\\u[0-9a-fA-F]{4}', String.Escape),
+ (r'\\.', String),
+ (r'[^\\"]+', String),
+ ],
+ }
diff --git a/tests/examplefiles/capdl_example.cdl b/tests/examplefiles/capdl_example.cdl
new file mode 100644
index 00000000..050e56a6
--- /dev/null
+++ b/tests/examplefiles/capdl_example.cdl
@@ -0,0 +1,64 @@
+#ifdef ARCH_ARM
+arch arm11
+#else
+arch ia32
+#endif
+
+objects {
+ my_ep = ep /* A synchronous endpoint */
+
+ /* Two thread control blocks */
+ tcb1 = tcb
+ tcb2 = tcb
+
+ /* Four frames of physical memory */
+ frame1 = frame (4k)
+ frame2 = frame (4k)
+ frame3 = frame (4k)
+ frame4 = frame (4k)
+
+ /* Two page tables */
+ pt1 = pt
+ pt2 = pt
+
+ /* Two page directories */
+ pd1 = pd
+ pd2 = pd
+
+ /* Two capability nodes */
+ cnode1 = cnode (2 bits)
+ cnode2 = cnode (3 bits)
+}
+caps {
+ cnode1 {
+ 0x1: frame1 (RW) /* read/write */
+ 0x2: my_ep (R) /* read-only */
+ }
+ cnode2 {
+ 0x1: my_ep (W) /* write-only */
+ }
+ tcb1 {
+ vspace: pd1
+ ipc_buffer_slot: frame1
+ cspace: cnode1
+ }
+ pd1 {
+ 0x10: pt1
+ }
+ pt1 {
+ 0x8: frame1 (RW)
+ 0x9: frame2 (R)
+ }
+ tcb2 {
+ vspace: pd2
+ ipc_buffer_slot: frame3
+ cspace: cnode2
+ }
+ pd2 {
+ 0x10: pt2
+ }
+ pt2 {
+ 0x10: frame3 (RW)
+ 0x12: frame4 (R)
+ }
+}
diff --git a/tests/examplefiles/durexmania.aheui b/tests/examplefiles/durexmania.aheui
new file mode 100644
index 00000000..89654c00
--- /dev/null
+++ b/tests/examplefiles/durexmania.aheui
@@ -0,0 +1,4 @@
+우주메이저☆듀렉스전도사♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♂♀♡먊
+삶은밥과야근밥샤주세양♡밥사밥사밥사밥사밥사땅땅땅빵☆따밦내발따밦다빵맣밥밥밥내놔밥줘밥밥밥밗땅땅땅박밝땅땅딻타밟타맣밦밣따박타맣밦밣따박타맣밦밣따박타맣박빵빵빵빵따따따따맣삶몲
+Original Source by @harunene // Run it on AheuiChem(http://yoo2001818.github.io/AheuiChem/)
+https://gist.github.com/item4/ca870a63b390da6cc6f1
diff --git a/tests/examplefiles/example.bat b/tests/examplefiles/example.bat
index 596f65de..2b45d2bc 100644
--- a/tests/examplefiles/example.bat
+++ b/tests/examplefiles/example.bat
@@ -205,5 +205,7 @@ for /f "tokens=2 delims==" %%G in ( 'assoc %+;/p extension'),%'
) &>nul ver
if errorlevel 0 if not errorlevel 1 set /a _passed+=1
goto :eof
+FOR /F %%a IN ('%%c%%') DO %%a
+rem %x% %x% %x% %x% %x% %x% %x% %x% %x% %x% %x% %x% %x% %x% %x% %x%
:/?
goto :fail
diff --git a/tests/examplefiles/example.juttle b/tests/examplefiles/example.juttle
new file mode 100644
index 00000000..ae861996
--- /dev/null
+++ b/tests/examplefiles/example.juttle
@@ -0,0 +1,110 @@
+/* Block comment */
+/*
+ Multiline block
+ comment
+*/
+
+// inline comment
+function juttleFunction(arg) {
+ if (arg == null) {
+ return null;
+ }
+ else if (arg == 0) {
+ return 'zero';
+ }
+ else if (arg == 1) {
+ return "one";
+ }
+ else {
+ return 1.1;
+ }
+}
+
+reducer juttleReducer(field) {
+ var x = 0;
+ function update() {
+ x = *field;
+ }
+
+ function result() {
+ return x;
+ }
+}
+
+sub myemit(limit) {
+ emit -limit limit
+}
+
+input test: text -default 'input';
+const object = {
+ xyz: 123,
+ name: 'something'
+};
+
+const array = [
+ :2016-01-01:,
+ :2016-01-01T01:00:00:,
+ :2016-01-01T01:00:00.000:,
+ :2016-01-01T01:00:00.000Z:,
+ :2016-01-01T01:00:00.000-0800:,
+ :2016-01-01T01:00:00.000-08:00:,
+ :00:00:01:,
+ :00:00:00.001:,
+ :now:,
+ :beginning:,
+ :end:,
+ :forever:,
+ :yesterday:,
+ :today:,
+ :tomorrow:,
+ :1:,
+ :1.1:,
+ :1s:,
+ :1 second:,
+ :1 seconds:,
+ :100ms:,
+ :100 millisecond:,
+ :100 milliseconds:,
+ :1d:,
+ :1 day:,
+ :1 days:,
+ :.2h:,
+ :1.2h:,
+ :.2 hour:,
+ :1.2 hours:,
+ :.5d:,
+ :1.5d:,
+ :.5 day:,
+ :1.5 days:,
+ :5m:,
+ :5 minutes:,
+ :10w:,
+ :10 weeks:,
+ :10M:,
+ :10 months:,
+ :100y:,
+ :100 years:,
+ :1 year and 2 months and 2 days:
+];
+
+emit
+ | batch :10 minutes:
+ | filter x=true
+ | head 1
+ | join
+ | keep x
+ | pace -every :1 minute:
+ | pass
+ | put y=false
+ | remove z
+ | sequence
+ | skip 1
+ | sort field -desc
+ | split field
+ | tail 10
+ | unbatch
+ | uniq field
+;
+
+read adapter -last :day: 'search' AND field~/pattern/ OR field == 'string'
+ | write adapter
diff --git a/tests/examplefiles/example.lua b/tests/examplefiles/example.lua
index 0289e58c..8ecd6a13 100644
--- a/tests/examplefiles/example.lua
+++ b/tests/examplefiles/example.lua
@@ -247,4 +247,28 @@ function AucAdvanced.Debug.Assert(test, message)
return DebugLib.Assert(addonName, test, message)
end
+--[==[
+Here follow further tests of Lua syntax.
+]]==]
+---[[
+local t = {
+ [ [[
+x
+]==] \]]]=1|2; a={b={c={}}},
+ 1, 1., 1.2, .2, 1e3, 1.e3, 1.2e3, .2e3, 1.2e+3, 1.2E-3;
+ 0xA, 0Xa, 0xA., 0x.F, 0xA.F, 0xA.Fp1, 0xA.FP+1, 0Xa.fp-1;
+}
+function t.f()
+ goto eof
+ os.exit()
+ :: eof ::
+end
+
+function t . a --[==[x]==] .b --[==[y]==] --
+-- () end
+ . c : d (file)
+ return '.\a.\b.\f.\n.\r.\t.\v.\\.\".\'.\
+.\z
+ .\0.\00.\000.\0000.\xFa.\u{1}.\u{1234}'
+end
diff --git a/tests/examplefiles/example.ng2 b/tests/examplefiles/example.ng2
new file mode 100644
index 00000000..0f424aca
--- /dev/null
+++ b/tests/examplefiles/example.ng2
@@ -0,0 +1,11 @@
+<div>
+ <p>{{order.DueTime | date:'d. MMMM yyyy HH:mm'}}</p>
+ <p>Status: {{order.OrderState}}</p>
+ <button (click)="deleteOrder()" *ngIf="cancelable" [value]="test" [(twoWayTest)]="foo.bar">Remove</button>
+ <ul>
+ <li *ngFor="#meal of order.Positions">
+ {{meal.Name}}
+ </li>
+ </ul>
+ <p>Preis: <b>{{order.TotalPrice | currency:'EUR':true:'1.2-2'}}</b></p>
+</div> \ No newline at end of file
diff --git a/tests/examplefiles/example.sbl b/tests/examplefiles/example.sbl
new file mode 100644
index 00000000..94efada5
--- /dev/null
+++ b/tests/examplefiles/example.sbl
@@ -0,0 +1,109 @@
+/* Stemmer for Esperanto in UTF-8 */
+
+strings ()
+
+integers ()
+
+booleans ( foreign )
+
+routines (
+ apostrophe
+ canonical_form
+ correlative
+ interjection
+ short_word
+ standard_suffix
+ unuj
+)
+
+externals ( stem )
+
+groupings ( vowel aiou ao ou )
+
+stringdef a' decimal '225'
+stringdef e' hex 'E9'
+stringdef i' hex 'ED'
+stringdef o' hex ' f3'
+stringdef u' hex 'fa '
+
+stringdef cx hex '0109'
+stringdef gx hex '011D'
+stringdef hx hex '0125'
+stringdef jx hex '0135'
+stringdef sx hex '015D'
+stringdef ux hex '016D'
+
+define canonical_form as repeat (
+ [substring]
+ among (
+stringescapes //
+ '/a'/' (<- 'a' set foreign)
+ '/e'/' (<- 'e' set foreign)
+ '/i'/' (<- 'i' set foreign)
+ '/o'/' (<- 'o' set foreign)
+ '/u'/' (<- 'u' set foreign)
+stringescapes `'
+ 'cx' (<- '`cx'')
+ 'gx' (<- '`gx'')
+ 'hx' (<- '`hx'')
+ 'jx' (<- '`jx'')
+ 'sx' (<- '`sx'')
+ 'ux' (<- '`ux'')
+ '' (next)
+ )
+)
+
+backwardmode (
+ stringescapes { }
+
+ define apostrophe as (
+ (['un{'}'] atlimit <- 'unu') or
+ (['l{'}'] atlimit <- 'la') or
+ (['{'}'] <- 'o')
+ )
+
+ define vowel 'aeiou'
+ define aiou vowel - 'e'
+ define ao 'ao'
+ define ou 'ou'
+
+ define short_word as not (loop (maxint * 0 + 4 / 2) gopast vowel)
+
+ define interjection as (
+ among ('adia{ux}' 'aha' 'amen' 'hola' 'hura' 'mia{ux}' 'muu' 'oho')
+ atlimit
+ )
+
+ define correlative as (
+ []
+ // Ignore -al, -am, etc. since they can't be confused with suffixes.
+ test (
+ ('a' or (try 'n'] 'e') or (try 'n' try 'j'] ou))
+ 'i'
+ try ('k' or 't' or '{cx}' or 'nen')
+ atlimit
+ )
+ delete
+ )
+
+ define unuj as (
+ [try 'n' 'j'] 'unu' atlimit delete
+ )
+
+ define standard_suffix as (
+ [
+ try ((try 'n' try 'j' ao) or (try 's' aiou) or (try 'n' 'e'))
+ try '-' try 'a{ux}'
+ ] delete
+ )
+)
+
+define stem as (
+ do canonical_form
+ not foreign
+ backwards (
+ do apostrophe
+ short_word or interjection or
+ correlative or unuj or do standard_suffix
+ )
+)
diff --git a/tests/examplefiles/example.tasm b/tests/examplefiles/example.tasm
new file mode 100644
index 00000000..d7202ffb
--- /dev/null
+++ b/tests/examplefiles/example.tasm
@@ -0,0 +1,527 @@
+;----------------------------------------------------------------------------;
+; Does A* pathfinding for rockraiders and vehicles
+;
+; Copyright 2015 Ruben De Smet
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are
+; met:
+;
+; (1) Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+;
+; (2) Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+;
+; (3) The name of the author may not be used to
+; endorse or promote products derived from this software without
+; specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+; IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+; POSSIBILITY OF SUCH DAMAGE.
+;
+;----------------------------------------------------------------------------;
+
+IDEAL
+P386
+MODEL FLAT, C
+ASSUME cs:_TEXT,ds:FLAT,es:FLAT,fs:FLAT,gs:FLAT
+
+INCLUDE "ASTAR.INC"
+INCLUDE "READLVL.INC"
+INCLUDE "DEBUG.INC"
+
+STRUC TPriorityField
+ heuristic dd ?
+ distance dd ?
+ x db ?
+ y db ?
+ fromx db ?
+ fromy db ?
+ENDS
+
+STRUC TField
+ distance dd ?
+ x db ?
+ y db ?
+ENDS
+
+CODESEG
+
+PROC getPath
+ USES ecx
+ ARG @@tgtx:dword, \
+ @@tgty:dword \
+ RETURNS eax, ebx ; eax contains x, ebx contains y
+
+ call getLevelWidth
+ imul eax, [@@tgty]
+ add eax, [@@tgtx]
+ imul eax, SIZE TField
+ add eax, offset backtraceGraph
+ mov ecx, eax
+
+ xor eax, eax
+ xor ebx, ebx
+
+ mov al, [(TField ptr ecx).x]
+ mov bl, [(TField ptr ecx).y]
+
+ ret
+ENDP getPath
+
+PROC findPath
+ ; eax will contain a 1 when a path has been found
+ ; 0 otherwise.
+ ARG @@srcx:dword, \
+ @@srcy:dword, \
+ @@tgtx:dword, \
+ @@tgty:dword, \
+ @@type:dword \
+ RETURNS eax
+
+ ; Check whether the target field is "allowed" for
+ ; the selected vehicle or rock raider
+ call getField, [@@tgtx], [@@tgty]
+ mov al, [byte ptr eax]
+ and eax, 0FFh
+
+ add eax, offset actionTable
+ mov eax, [eax]
+ and eax, [@@type] ; TODO: for now, rock raider is hard coded
+ jnz @canGoToTarget
+
+ mov eax, 0
+ ret
+@canGoToTarget:
+
+ call cleanData
+ mov eax, [@@type]
+ mov [currentType], eax
+
+ mov eax, [@@srcx]
+ mov [currentOpen.x], al
+ mov eax, [@@srcy]
+ mov [currentOpen.y], al
+
+ call distance, [@@srcx], [@@srcy], [@@tgtx], [@@tgty]
+ ; eax <- distance
+ call addOpen, [@@srcx], [@@srcy], eax, 0
+
+@openListNotEmpty:
+ call popOpen
+ cmp eax, 0
+ je @openListEmpty
+
+ call addToMap
+
+ call addClosed
+
+ mov eax, [@@tgtx]
+ cmp [currentOpen.x], al
+ jne @nextOpen
+ mov eax, [@@tgty]
+ cmp [currentOpen.y], al
+ jne @nextOpen
+
+ jmp @routeFound
+
+ @nextOpen:
+ call addNeighbours, [@@tgtx], [@@tgty]
+
+ jmp @openListNotEmpty
+
+@openListEmpty:
+ mov eax, 0
+ ret
+
+@routeFound:
+ mov eax, 1
+ ret
+ENDP findPath
+
+PROC addToMap
+ USES eax, ecx
+
+ call getLevelWidth
+ xor ecx, ecx
+ mov cl, [currentOpen.y]
+ imul eax, ecx
+ mov cl, [currentOpen.x]
+ add eax, ecx
+ imul eax, SIZE TField
+ add eax, offset backtraceGraph
+
+ mov ecx, [currentOpen.distance]
+ cmp [(TField ptr eax).distance], ecx
+ jbe @dontAdd
+
+ mov [(TField ptr eax).distance], ecx
+ mov cl, [currentOpen.fromx]
+ mov [(TField ptr eax).x], cl
+ mov cl, [currentOpen.fromy]
+ mov [(TField ptr eax).y], cl
+
+@dontAdd:
+ ret
+ENDP addToMap
+
+; Is closed checks whether the field considered is "closed" for being added to the open list.
+; So, it also checks whether we can go on the selected field.
+PROC isClosed
+ USES ebx, ecx, edx
+ ARG @@x:dword, \
+ @@y:dword RETURNS eax
+
+ ; Check bounds first:
+
+ call getLevelWidth
+ cmp [@@x], eax
+ ja notWithinBounds ; ja considers -1 > 10
+
+ call getLevelHeight
+ cmp [@@y], eax
+ ja notWithinBounds
+
+ ; Check whether this field is "allowed" for
+ ; the selected vehicle or rock raider
+ call getField, [@@x], [@@y]
+ mov al, [byte ptr eax]
+ and eax, 0FFh
+
+ add eax, offset actionTable
+ mov eax, [eax]
+ and eax, [currentType] ; TODO: for now, rock raider is hard coded
+ jnz @canGoHere
+
+
+ inc eax ; mov eax, 1
+ ret
+
+@canGoHere:
+
+ ; Getting here means the field is okay to walk/fly/whatever on
+
+ xor ecx, ecx
+ mov cx, [closedlistSize]
+ cmp cx, 0 ; If empty, return 0
+ jne @closedNotEmpty
+
+ mov eax, 0
+ ret
+
+@closedNotEmpty:
+ mov ebx, offset closedlist
+
+@loopClosed:
+ mov edx, [@@x]
+ cmp [(TField ptr ebx).x], dl
+ jne @nextClosed
+ mov edx, [@@y]
+ cmp [(TField ptr ebx).y], dl
+ jne @nextClosed
+
+ ; If reached here, yep, contained in closed list
+ mov eax, 1
+ ret
+
+ @nextClosed:
+ add ebx, SIZE TField
+ dec ecx
+ jnz @loopClosed
+
+ mov eax, 0
+ ret
+
+notWithinBounds:
+ mov eax, 1
+ ret
+ENDP isClosed
+
+PROC addNeighbours
+ USES eax, ebx, ecx, edx
+ ARG @@tgtx:dword, \
+ @@tgty:dword
+ ; Push all neighbours of currentOpen on openList
+
+ xor ebx, ebx
+ xor ecx, ecx
+
+ mov bl, [currentOpen.x]
+ mov cl, [currentOpen.y]
+ mov edx, [currentOpen.distance]
+ inc edx ; Next distance is one more.
+
+ ; Up
+ dec ecx
+ call isClosed, ebx, ecx
+ cmp eax, 0
+ jne @noUp
+ call distance, ebx, ecx, [@@tgtx], [@@tgty]
+ add eax, edx
+ call addOpen, ebx, ecx, eax, edx
+ @noUp:
+ inc ecx
+
+ ; Right
+ inc ebx
+ call isClosed, ebx, ecx
+ cmp eax, 0
+ jne @noRight
+ call distance, ebx, ecx, [@@tgtx], [@@tgty]
+ add eax, edx
+ call addOpen, ebx, ecx, eax, edx
+ @noRight:
+ dec ebx
+
+ ; Left
+ dec ebx
+ call isClosed, ebx, ecx
+ cmp eax, 0
+ jne @noLeft
+ call distance, ebx, ecx, [@@tgtx], [@@tgty]
+ add eax, edx
+ call addOpen, ebx, ecx, eax, edx
+ @noLeft:
+ inc ebx
+
+ ; Down
+ inc ecx
+ call isClosed, ebx, ecx
+ cmp eax, 0
+ jne @noDown
+ call distance, ebx, ecx, [@@tgtx], [@@tgty]
+ add eax, edx
+ call addOpen, ebx, ecx, eax, edx
+ @noDown:
+ dec ecx
+
+ ret
+ENDP addNeighbours
+
+PROC popOpen
+ ARG RETURNS eax
+ USES ebx, ecx, edx, esi, edi
+ ; eax contains the smallest current heuristic
+ ; ebx contains the index of that field
+
+ cmp [openlistSize], 0 ; If empty, return 0
+ jne @goForth
+
+ mov eax, 0
+ ret
+
+@goForth:
+
+ mov eax, 0FFFFFFFFh ; Longest distance possible in 32 bits.
+ xor ebx, ebx
+ xor ecx, ecx ; ecx contains the current index
+
+@searchFurther:
+ mov edx, ecx
+ imul edx, SIZE TPriorityField
+ cmp [(TPriorityField ptr (openlist + edx)).heuristic], eax
+ ja @notBetter
+ ; Better guess found, put right values in eax and ebx
+ mov eax, [(TPriorityField ptr (openlist + edx)).heuristic]
+ mov ebx, ecx
+
+@notBetter:
+
+ inc ecx
+ cmp cx, [openlistSize]
+ jne @searchFurther
+
+ ; By now, we have found the right item to pop from the priorityqueue.
+
+ ; Move the correct item in currentOpen
+ mov ecx, SIZE TPriorityField
+ mov esi, ebx
+ imul esi, ecx
+ add esi, offset openlist
+
+ mov edi, offset currentOpen
+ rep movsb
+
+ ; Now make the remove the thing from the vector
+
+ xor ecx, ecx
+ mov cx, [openlistSize]
+ sub ecx, ebx
+ dec ecx
+ imul ecx, SIZE TPriorityField
+ mov edi, esi
+ sub edi, SIZE TPriorityField
+ rep movsb
+
+ dec [openlistSize]
+ mov eax, 1
+ ret
+ENDP popOpen
+
+PROC addClosed
+ USES eax, ebx
+
+ xor ebx, ebx
+ xor eax, eax
+
+ mov bx, [closedlistSize]
+ imul ebx, SIZE TField
+ add ebx, offset closedlist ; ebx contains the target TField
+
+ mov al, [currentOpen.x]
+ mov [(TField ptr ebx).x], al
+ mov al, [currentOpen.y]
+ mov [(TField ptr ebx).y], al
+ mov eax, [currentOpen.distance]
+ mov [(TField ptr ebx).distance], eax
+
+ inc [closedlistSize]
+ cmp [closedlistSize], CLOSED_LIST_SIZE_MAX
+ jne @noProblemWithClosedVector
+
+ xor eax, eax
+ mov ax, [closedlistSize]
+ call crash, offset closedOutOfMemory, eax
+
+@noProblemWithClosedVector:
+ ret
+ENDP addClosed
+
+PROC addOpen
+ USES eax, ebx
+ ARG @@x:dword, \
+ @@y:dword, \
+ @@priority:dword, \
+ @@distance:dword
+
+ xor eax, eax
+ mov ax, [openlistSize]
+ imul eax, SIZE TPriorityField
+ add eax, offset openlist
+
+ mov ebx, [@@x]
+ mov [(TPriorityField ptr eax).x], bl
+ mov ebx, [@@y]
+ mov [(TPriorityField ptr eax).y], bl
+
+ mov bl, [currentOpen.x]
+ mov [(TPriorityField ptr eax).fromx], bl
+ mov bl, [currentOpen.y]
+ mov [(TPriorityField ptr eax).fromy], bl
+
+ mov ebx, [@@priority]
+ mov [(TPriorityField ptr eax).heuristic], ebx
+ mov ebx, [@@distance]
+ mov [(TPriorityField ptr eax).distance], ebx
+
+ inc [openlistSize]
+ cmp [openlistSize], OPEN_LIST_SIZE_MAX
+ jne @noProblem
+
+ xor eax, eax
+ mov ax, [openlistSize]
+ call crash, offset openOutOfMemory, eax
+
+@noProblem:
+ ret
+ENDP
+
+PROC distance
+ USES ebx
+ ARG @@srcx:dword, \
+ @@srcy:dword, \
+ @@tgtx:dword, \
+ @@tgty:dword \
+ RETURNS eax
+
+ mov eax, [@@srcx]
+ sub eax, [@@tgtx]
+
+ jns @noSignChangex
+ neg eax
+
+ @noSignChangex:
+
+ mov ebx, [@@srcy]
+ sub ebx, [@@tgty]
+
+ jns @noSignChangey
+ neg ebx
+
+ @noSignChangey:
+ add eax, ebx
+ ret
+ENDP distance
+
+PROC cleanData
+ USES eax, ecx
+ mov [openlistSize], 0
+ mov [closedlistSize], 0
+
+ mov [currentOpen.x], -1
+ mov [currentOpen.y], -1
+ mov [currentOpen.distance], 0
+
+ call getLevelWidth
+ mov ecx, eax
+ call getLevelHeight
+ imul ecx, eax
+
+ mov eax, offset backtraceGraph
+@fieldIter:
+ mov [(TField ptr eax).distance], 0ffffffffh ; Set to approximately +inf
+ mov [(TField ptr eax).x], 0
+ mov [(TField ptr eax).y], 0
+ add eax, SIZE TField
+ dec ecx
+ jnz @fieldIter
+
+ ret
+ENDP cleanData
+
+DATASEG
+
+openOutOfMemory db "Out of openlistSize memory. Hi dev: Please increase$"
+closedOutOfMemory db "Out of closedlistSize memory. Hi dev: Please increase$"
+
+; power | discover | walking | sailing | flying
+actionTable db 00001101b, \ ;EMPTY
+ 00001101b, \ ;RUBBLE
+ 00000000b, \ ;GRAVEL
+ 00000000b, \ ;LOOSE ROCK
+ 00000000b, \ ;HARD ROCK
+ 00000000b, \ ;MASSIVE ROCK
+ 00000000b, \ ;KRISTAL SOURCE
+ 00000000b, \ ;OREROCK
+ 00001011b, \ ;WATER
+ 00001001b, \ ;LAVA
+ 00001101b, \ ;SNAIL HOLE
+ 00001101b, \ ;EROSION
+ 00011101b, \ ;POWER PATH
+ 00011101b, \ ;BUILDING POWER PATH
+ 00011000b \ ;BUILDING
+
+UDATASEG
+
+currentType dd ?
+currentOpen TPriorityField ?
+
+openlist TPriorityField OPEN_LIST_SIZE_MAX dup(?)
+openlistSize dw ?
+closedlist TField CLOSED_LIST_SIZE_MAX dup(?)
+closedlistSize dw ?
+backtraceGraph TField MAX_LEVEL_SIZE dup(?)
+
+END
diff --git a/tests/examplefiles/example.whiley b/tests/examplefiles/example.whiley
new file mode 100644
index 00000000..74b39370
--- /dev/null
+++ b/tests/examplefiles/example.whiley
@@ -0,0 +1,296 @@
+/**
+ * Example Whiley program, taken from the Whiley benchmark suite.
+ * https://github.com/Whiley/WyBench/blob/master/src/101_interpreter/Main.whiley
+ */
+
+import whiley.lang.System
+import whiley.lang.Int
+import whiley.io.File
+import string from whiley.lang.ASCII
+import char from whiley.lang.ASCII
+
+// ====================================================
+// A simple calculator for expressions
+// ====================================================
+
+constant ADD is 0
+constant SUB is 1
+constant MUL is 2
+constant DIV is 3
+
+// binary operation
+type BOp is (int x) where ADD <= x && x <= DIV
+type BinOp is { BOp op, Expr lhs, Expr rhs }
+
+// variables
+type Var is { string id }
+
+// list access
+type ListAccess is {
+ Expr src,
+ Expr index
+}
+
+// expression tree
+type Expr is int | // constant
+ Var | // variable
+ BinOp | // binary operator
+ Expr[] | // array constructor
+ ListAccess // list access
+
+// values
+type Value is int | Value[]
+
+// stmts
+type Print is { Expr rhs }
+type Set is { string lhs, Expr rhs }
+type Stmt is Print | Set
+
+// ====================================================
+// Expression Evaluator
+// ====================================================
+
+type RuntimeError is { string msg }
+type Environment is [{string k, Value v}]
+
+// Evaluate an expression in a given environment reducing either to a
+// value, or a runtime error. The latter occurs if evaluation gets
+// "stuck" (e.g. expression is // not well-formed)
+function evaluate(Expr e, Environment env) -> Value | RuntimeError:
+ //
+ if e is int:
+ return e
+ else if e is Var:
+ return env[e.id]
+ else if e is BinOp:
+ Value|RuntimeError lhs = evaluate(e.lhs, env)
+ Value|RuntimeError rhs = evaluate(e.rhs, env)
+ // check if stuck
+ if !(lhs is int && rhs is int):
+ return {msg: "arithmetic attempted on non-numeric value"}
+ // switch statement would be good
+ if e.op == ADD:
+ return lhs + rhs
+ else if e.op == SUB:
+ return lhs - rhs
+ else if e.op == MUL:
+ return lhs * rhs
+ else if rhs != 0:
+ return lhs / rhs
+ return {msg: "divide-by-zero"}
+ else if e is Expr[]:
+ [Value] r = []
+ for i in e:
+ Value|RuntimeError v = evaluate(i, env)
+ if v is RuntimeError:
+ return v
+ else:
+ r = r ++ [v]
+ return r
+ else if e is ListAccess:
+ Value|RuntimeError src = evaluate(e.src, env)
+ Value|RuntimeError index = evaluate(e.index, env)
+ // santity checks
+ if src is [Value] && index is int && index >= 0 && index < |src|:
+ return src[index]
+ else:
+ return {msg: "invalid list access"}
+ else:
+ return 0 // dead-code
+
+// ====================================================
+// Expression Parser
+// ====================================================
+
+type State is { string input, int pos }
+type SyntaxError is { string msg, int start, int end }
+
+function SyntaxError(string msg, int start, int end) -> SyntaxError:
+ return { msg: msg, start: start, end: end }
+
+// Top-level parse method
+function parse(State st) -> (Stmt,State)|SyntaxError:
+ //
+ Var keyword, Var v
+ Expr e
+ int start = st.pos
+ //
+ keyword,st = parseIdentifier(st)
+ switch keyword.id:
+ case "print":
+ any r = parseAddSubExpr(st)
+ if !(r is SyntaxError):
+ e,st = r
+ return {rhs: e},st
+ else:
+ return r // error case
+ case "set":
+ st = parseWhiteSpace(st)
+ v,st = parseIdentifier(st)
+ any r = parseAddSubExpr(st)
+ if !(r is SyntaxError):
+ e,st = r
+ return {lhs: v.id, rhs: e},st
+ else:
+ return r // error case
+ default:
+ return SyntaxError("unknown statement",start,st.pos-1)
+
+function parseAddSubExpr(State st) -> (Expr, State)|SyntaxError:
+ //
+ Expr lhs, Expr rhs
+ // First, pass left-hand side
+ any r = parseMulDivExpr(st)
+ //
+ if r is SyntaxError:
+ return r
+ //
+ lhs,st = r
+ st = parseWhiteSpace(st)
+ // Second, see if there is a right-hand side
+ if st.pos < |st.input| && st.input[st.pos] == '+':
+ // add expression
+ st.pos = st.pos + 1
+ r = parseAddSubExpr(st)
+ if !(r is SyntaxError):
+ rhs,st = r
+ return {op: ADD, lhs: lhs, rhs: rhs},st
+ else:
+ return r
+ else if st.pos < |st.input| && st.input[st.pos] == '-':
+ // subtract expression
+ st.pos = st.pos + 1
+ r = parseAddSubExpr(st)
+ if !(r is SyntaxError):
+ rhs,st = r
+ return {op: SUB, lhs: lhs, rhs: rhs},st
+ else:
+ return r
+ // No right-hand side
+ return (lhs,st)
+
+function parseMulDivExpr(State st) -> (Expr, State)|SyntaxError:
+ // First, parse left-hand side
+ Expr lhs, Expr rhs
+ any r = parseTerm(st)
+ if r is SyntaxError:
+ return r
+ //
+ lhs,st = r
+ st = parseWhiteSpace(st)
+ // Second, see if there is a right-hand side
+ if st.pos < |st.input| && st.input[st.pos] == '*':
+ // add expression
+ st.pos = st.pos + 1
+ r = parseMulDivExpr(st)
+ if !(r is SyntaxError):
+ rhs,st = r
+ return {op: MUL, lhs: lhs, rhs: rhs}, st
+ else:
+ return r
+ else if st.pos < |st.input| && st.input[st.pos] == '/':
+ // subtract expression
+ st.pos = st.pos + 1
+ r = parseMulDivExpr(st)
+ if !(r is SyntaxError):
+ rhs,st = r
+ return {op: DIV, lhs: lhs, rhs: rhs}, st
+ else:
+ return r
+ // No right-hand side
+ return (lhs,st)
+
+function parseTerm(State st) -> (Expr, State)|SyntaxError:
+ //
+ st = parseWhiteSpace(st)
+ if st.pos < |st.input|:
+ if ASCII.isLetter(st.input[st.pos]):
+ return parseIdentifier(st)
+ else if ASCII.isDigit(st.input[st.pos]):
+ return parseNumber(st)
+ else if st.input[st.pos] == '[':
+ return parseList(st)
+ //
+ return SyntaxError("expecting number or variable",st.pos,st.pos)
+
+function parseIdentifier(State st) -> (Var, State):
+ //
+ string txt = ""
+ // inch forward until end of identifier reached
+ while st.pos < |st.input| && ASCII.isLetter(st.input[st.pos]):
+ txt = txt ++ [st.input[st.pos]]
+ st.pos = st.pos + 1
+ return ({id:txt}, st)
+
+function parseNumber(State st) -> (Expr, State)|SyntaxError:
+ // inch forward until end of identifier reached
+ int start = st.pos
+ while st.pos < |st.input| && ASCII.isDigit(st.input[st.pos]):
+ st.pos = st.pos + 1
+ //
+ int|null iv = Int.parse(st.input[start..st.pos])
+ if iv == null:
+ return SyntaxError("Error parsing number",start,st.pos)
+ else:
+ return iv, st
+
+function parseList(State st) -> (Expr, State)|SyntaxError:
+ //
+ st.pos = st.pos + 1 // skip '['
+ st = parseWhiteSpace(st)
+ [Expr] l = [] // initial list
+ bool firstTime = true
+ while st.pos < |st.input| && st.input[st.pos] != ']':
+ if !firstTime && st.input[st.pos] != ',':
+ return SyntaxError("expecting comma",st.pos,st.pos)
+ else if !firstTime:
+ st.pos = st.pos + 1 // skip ','
+ firstTime = false
+ any r = parseAddSubExpr(st)
+ if r is SyntaxError:
+ return r
+ else:
+ Expr e
+ e,st = r
+ // perform annoying error check
+ l = l ++ [e]
+ st = parseWhiteSpace(st)
+ st.pos = st.pos + 1
+ return l,st
+
+// Parse all whitespace upto end-of-file
+function parseWhiteSpace(State st) -> State:
+ while st.pos < |st.input| && ASCII.isWhiteSpace(st.input[st.pos]):
+ st.pos = st.pos + 1
+ return st
+
+// ====================================================
+// Main Method
+// ====================================================
+
+public method main(System.Console sys):
+ if(|sys.args| == 0):
+ sys.out.println("no parameter provided!")
+ else:
+ File.Reader file = File.Reader(sys.args[0])
+ string input = ASCII.fromBytes(file.readAll())
+
+ Environment env = Environment()
+ State st = {pos: 0, input: input}
+ while st.pos < |st.input|:
+ Stmt s
+ any r = parse(st)
+ if r is SyntaxError:
+ sys.out.println("syntax error: " ++ r.msg)
+ return
+ s,st = r
+ Value|RuntimeError v = evaluate(s.rhs,env)
+ if v is RuntimeError:
+ sys.out.println("runtime error: " ++ v.msg)
+ return
+ if s is Set:
+ env[s.lhs] = v
+ else:
+ sys.out.println(r)
+ st = parseWhiteSpace(st)
+
diff --git a/tests/examplefiles/fibonacci.tokigun.aheui b/tests/examplefiles/fibonacci.tokigun.aheui
new file mode 100644
index 00000000..afa2ca05
--- /dev/null
+++ b/tests/examplefiles/fibonacci.tokigun.aheui
@@ -0,0 +1,4 @@
+바싹반박나싼순
+뿌멓떠벌번멍뻐
+쌀삭쌀살다순옭
+어어선썬설썩옭
diff --git a/tests/examplefiles/guidance.smv b/tests/examplefiles/guidance.smv
new file mode 100644
index 00000000..671d1e1c
--- /dev/null
+++ b/tests/examplefiles/guidance.smv
@@ -0,0 +1,1124 @@
+--
+-- Shuttle Digital Autopilot
+-- by Sergey Berezin (berez@cs.cmu.edu)
+--
+MODULE cont_3eo_mode_select(start,smode5,vel,q_bar,apogee_alt_LT_alt_ref,
+ h_dot_LT_hdot_reg2,alpha_n_GRT_alpha_reg2,
+ delta_r_GRT_del_r_usp,v_horiz_dnrng_LT_0,
+ high_rate_sep,meco_confirmed)
+
+VAR cont_3EO_start: boolean;
+ RTLS_abort_declared: boolean;
+ region_selected : boolean;
+ m_mode: {mm102, mm103, mm601};
+ r: {reg-1, reg0, reg1, reg2, reg3, reg102};
+ step : {1,2,3,4,5,6,7,8,9,10, exit, undef};
+
+ASSIGN
+ init(cont_3EO_start) := FALSE;
+ init(m_mode) := {mm102, mm103};
+ init(region_selected) := FALSE;
+ init(RTLS_abort_declared) := FALSE;
+ init(r) := reg-1;
+ init(step) := undef;
+
+ next(step) :=
+ case
+ step = 1 & m_mode = mm102 : exit;
+ step = 1 : 2;
+ step = 2 & smode5 : 5;
+ step = 2 & vel = GRT_vi_3eo_max: exit;
+ step = 2 : 3;
+ step = 3 & vel = LEQ_vi_3eo_min : 6;
+ step = 3 : 4;
+ step = 4 & apogee_alt_LT_alt_ref: exit;
+ step = 4 : 6;
+ step = 5 : 6;
+ step = 6 & r = reg0 : exit;
+ step = 6 : 7;
+ step = 7 : 8;
+ step = 8 & q_bar = GRT_qbar_reg3 & !high_rate_sep : 10;
+ step = 8 : 9;
+ step = 9 : 10;
+ step = 10: exit;
+ next(start): 1;
+ step = exit : undef;
+ TRUE: step;
+ esac;
+
+ next(cont_3EO_start) :=
+ case
+ step = 1 & m_mode = mm102 : TRUE;
+ step = 10 & meco_confirmed : TRUE;
+ TRUE : cont_3EO_start;
+ esac;
+
+ next(r) :=
+ case
+ step = 1 & m_mode = mm102 : reg102;
+ step = 2 & !smode5 & vel = GRT_vi_3eo_max: reg0;
+ step = 4 & apogee_alt_LT_alt_ref: reg0;
+ step = 5 & v_horiz_dnrng_LT_0 & delta_r_GRT_del_r_usp : reg0;
+ step = 8 & q_bar = GRT_qbar_reg3 & !high_rate_sep : reg3;
+ step = 9: case
+ (h_dot_LT_hdot_reg2 & alpha_n_GRT_alpha_reg2 &
+ q_bar = GRT_qbar_reg1) | high_rate_sep : reg2;
+ TRUE : reg1;
+ esac;
+ next(step) = 1 : reg-1;
+ TRUE: r;
+ esac;
+
+ next(RTLS_abort_declared) :=
+ case
+ step = 10 & meco_confirmed & m_mode = mm103 : TRUE;
+ TRUE: RTLS_abort_declared;
+ esac;
+
+ next(m_mode) :=
+ case
+ step = 10 & meco_confirmed & m_mode = mm103 : mm601;
+ TRUE: m_mode;
+ esac;
+
+ next(region_selected) :=
+ case
+ next(step) = 1 : FALSE;
+ next(step) = exit : TRUE;
+ TRUE : region_selected;
+ esac;
+
+MODULE cont_3eo_guide(start,cont_3EO_start, mode_select_completed, et_sep_cmd,
+ h_dot_LT_0, q_bar_a_GRT_qbar_max_sep, m_mode, r0,
+ cont_minus_z_compl, t_nav-t_et_sep_GRT_dt_min_z_102,
+ ABS_q_orb_GRT_q_minus_z_max, ABS_r_orb_GRT_r_minus_z_max,
+ excess_OMS_propellant, q_bar_a_LT_qbar_oms_dump,
+ entry_mnvr_couter_LE_0, rcs_all_jet_inhibit,
+ alt_GRT_alt_min_102_dump, t_nav-t_gmtlo_LT_t_dmp_last,
+ pre_sep, cond_18, q_orb_LT_0, ABS_alf_err_LT_alf_sep_err,
+ cond_20b, cond_21, ABS_beta_n_GRT_beta_max, cond_24, cond_26,
+ cond_27, cond_29, mm602_OK)
+VAR
+ step: {1,a1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
+ b20, c20, d20, 21,22,23,24,25,26,27,28,29,exit, undef};
+ call_RTLS_abort_task : boolean;
+ first3: boolean; -- indicates if it is the first pass
+ first8: boolean;
+ first27: boolean;
+ s_unconv : boolean;
+ mode_2_indicator : boolean;
+ et_sep_man_initiate : boolean;
+ emerg_sep : boolean;
+ cont_3eo_pr_delay : {minus_z_reg1, minus_z_reg2,
+ minus_z_reg3, minus_z_reg4, minus_z_reg102, 0, 5};
+ etsep_y_drift : {undef, minus_z_reg1, minus_z_reg2,
+ minus_z_reg3, minus_z_reg4, minus_z_reg102, 0};
+ fwd_rcs_dump_enable : boolean;
+ fcs_accept_icnct : boolean;
+ oms_rcs_i_c_inh_ena_cmd : boolean;
+ orbiter_dump_ena : boolean;
+ frz_3eo : boolean;
+ high_rate_sep: boolean;
+ entry_gains : boolean;
+ cont_sep_cplt : boolean;
+ pch_cmd_reg4 : boolean;
+ alpha_ok : boolean;
+ r : {reg-1, reg0, reg1, reg2, reg3, reg4, reg102};
+ early_sep : boolean;
+--------------------------------------------
+----- Additional Variables -----------------
+--------------------------------------------
+ rtls_lo_f_d_delay : {undef, 0};
+ wcb2 : {undef, reg1_0, reg2_neg4, wcb2_3eo, reg4_0,
+ reg102_undef, post_sep_0};
+ q_gcb_i : {undef, quat_reg1, quat_reg2, quat_reg3, quat_reg4,
+ quat_reg102_undef, quat_entry_M50_to_cmdbody};
+ oms_nz_lim : {undef, oms_nz_lim_3eo, oms_nz_lim_iload, oms_nz_lim_std};
+ contingency_nz_lim : {undef, contingency_nz_lim_3eo,
+ contingency_nz_lim_iload, contingency_nz_lim_std};
+
+
+
+ASSIGN
+ init(entry_gains) := FALSE;
+ init(frz_3eo) := FALSE;
+ init(cont_3eo_pr_delay) := 5;
+ init(etsep_y_drift) := undef;
+ init(r) := reg-1;
+ init(step) := undef;
+ init(call_RTLS_abort_task) := FALSE;
+ init(first3) := TRUE;
+ init(first8) := TRUE;
+ init(first27) := TRUE;
+ init(cont_sep_cplt) := FALSE;
+ init(et_sep_man_initiate) := FALSE;
+ init(alpha_ok) := FALSE;
+ init(pch_cmd_reg4) := FALSE;
+
+-- Assumed initializations:
+
+ init(rtls_lo_f_d_delay) := undef;
+ init(wcb2) := undef;
+ init(q_gcb_i) := undef;
+ init(oms_nz_lim) := undef;
+ init(contingency_nz_lim) := undef;
+ init(oms_rcs_i_c_inh_ena_cmd) := FALSE;
+ init(orbiter_dump_ena) := FALSE;
+-- init(early_sep) := FALSE;
+
+-------------
+
+ next(step) := nextstep;
+
+ next(r) :=
+ case
+ step = a1 & (cont_3EO_start | mode_select_completed) : r0;
+ step = 21 & cond_21 : reg4;
+ step = 23 & ABS_beta_n_GRT_beta_max & !high_rate_sep : reg1;
+ TRUE : r;
+ esac;
+
+ next(first3) :=
+ case
+ step = 3 & cont_3EO_start : FALSE;
+ TRUE : first3;
+ esac;
+
+ next(first8) :=
+ case
+ step = 8 & excess_OMS_propellant & cont_3EO_start : FALSE;
+ TRUE : first8;
+ esac;
+
+ next(first27) :=
+ case
+ step = 27 : FALSE;
+ TRUE: first27;
+ esac;
+
+ next(s_unconv) :=
+ case
+ step = 3 : FALSE;
+ TRUE : s_unconv;
+ esac;
+
+ next(call_RTLS_abort_task) :=
+ case
+ step = 3 : TRUE;
+ TRUE : call_RTLS_abort_task;
+ esac;
+
+ next(mode_2_indicator) :=
+ case
+ step = 4 : TRUE;
+ TRUE : mode_2_indicator;
+ esac;
+
+ next(et_sep_man_initiate) :=
+ case
+ step = 5 & h_dot_LT_0 & q_bar_a_GRT_qbar_max_sep & m_mode != mm102 : TRUE;
+ step = 14 & pre_sep : TRUE;
+ step = 19 & q_orb_LT_0 : TRUE;
+ step = d20 : TRUE;
+ step = 26 & cond_26 : TRUE;
+ step = 29 & cond_29 : TRUE;
+ TRUE : et_sep_man_initiate;
+ esac;
+
+ next(emerg_sep) :=
+ case
+ next(step) = 1 : FALSE;
+ step = 5 & h_dot_LT_0 & q_bar_a_GRT_qbar_max_sep & m_mode != mm102: TRUE;
+ TRUE : emerg_sep;
+ esac;
+
+ next(cont_3eo_pr_delay) :=
+ case
+ next(step) = 1 : 5;
+ step = 5 & h_dot_LT_0 & q_bar_a_GRT_qbar_max_sep & m_mode != mm102 :
+ minus_z_reg3;
+ step = 7 & !cont_minus_z_compl & r = reg102 &
+ t_nav-t_et_sep_GRT_dt_min_z_102 &
+ (ABS_q_orb_GRT_q_minus_z_max | ABS_r_orb_GRT_r_minus_z_max) : 0;
+ step = 14 & pre_sep : minus_z_reg102;
+ step = 19 & q_orb_LT_0 : minus_z_reg4;
+ step = d20 : minus_z_reg3;
+ step = 26 & cond_26 : minus_z_reg2;
+ step = 27 & first27 : minus_z_reg1;
+ TRUE : cont_3eo_pr_delay;
+ esac;
+
+ next(etsep_y_drift) :=
+ case
+ step = 5 & h_dot_LT_0 & q_bar_a_GRT_qbar_max_sep & m_mode != mm102 :
+ minus_z_reg3;
+ step = 7 & !cont_minus_z_compl & r = reg102 &
+ t_nav-t_et_sep_GRT_dt_min_z_102 &
+ (ABS_q_orb_GRT_q_minus_z_max | ABS_r_orb_GRT_r_minus_z_max) : 0;
+ step = 14 & pre_sep : minus_z_reg102;
+ step = 19 & q_orb_LT_0 : minus_z_reg4;
+ step = d20 : minus_z_reg3;
+ step = 26 & cond_26 : minus_z_reg2;
+ step = 27 & first27 : minus_z_reg1;
+ TRUE : etsep_y_drift;
+ esac;
+
+ next(fwd_rcs_dump_enable) :=
+ case
+ step = 8 & excess_OMS_propellant & first8 : FALSE;
+ TRUE : fwd_rcs_dump_enable;
+ esac;
+
+ next(fcs_accept_icnct) :=
+ case
+ step = 9 & q_bar_a_LT_qbar_oms_dump & r != reg102 : TRUE;
+ TRUE : fcs_accept_icnct;
+ esac;
+
+ next(oms_rcs_i_c_inh_ena_cmd) :=
+ case
+-- next(step) = 1 & oms_rcs_i_c_inh_ena_cmd : {0,1};
+ next(step) = 1 & oms_rcs_i_c_inh_ena_cmd : FALSE; -- Assumed initialization
+ step = 9 & q_bar_a_LT_qbar_oms_dump & r != reg102 : TRUE;
+ TRUE : oms_rcs_i_c_inh_ena_cmd;
+ esac;
+
+ next(orbiter_dump_ena) :=
+ case
+ next(start) = TRUE : FALSE; -- Assumed initialization
+ step = 9 & q_bar_a_LT_qbar_oms_dump & r != reg102 : TRUE;
+ step = 13 & alt_GRT_alt_min_102_dump & t_nav-t_gmtlo_LT_t_dmp_last : TRUE;
+ TRUE : orbiter_dump_ena;
+ esac;
+
+ next(frz_3eo) :=
+ case
+ next(step) = 1 : FALSE;
+ step = 10 & entry_mnvr_couter_LE_0 & !rcs_all_jet_inhibit : FALSE;
+ step = 28 & !et_sep_man_initiate : TRUE;
+ TRUE : frz_3eo;
+ esac;
+
+ next(high_rate_sep) :=
+ case
+ step = 10 & entry_mnvr_couter_LE_0 & !rcs_all_jet_inhibit : FALSE;
+ step = 25 : TRUE;
+ TRUE : high_rate_sep;
+ esac;
+
+ next(entry_gains) :=
+ case
+ next(step) = 1 : FALSE;
+ step = 10 & entry_mnvr_couter_LE_0 & !rcs_all_jet_inhibit : TRUE;
+ TRUE : entry_gains;
+ esac;
+
+ next(cont_sep_cplt) :=
+ case
+ next(step) = 1 : FALSE;
+ step = 12 & mm602_OK : TRUE;
+ TRUE : cont_sep_cplt;
+ esac;
+
+ next(pch_cmd_reg4) :=
+ case
+ next(step) = 1 : FALSE;
+ step = 18 & !pch_cmd_reg4 & cond_18 : TRUE;
+ TRUE : pch_cmd_reg4;
+ esac;
+
+ next(alpha_ok) :=
+ case
+ next(step) = 1 : FALSE;
+ step = 20 & ABS_alf_err_LT_alf_sep_err : TRUE;
+ TRUE : alpha_ok;
+ esac;
+
+ next(early_sep) :=
+ case
+ step = 27 & first27 :
+ case
+ cond_27 : TRUE;
+ TRUE : FALSE;
+ esac;
+ TRUE : early_sep;
+ esac;
+
+--------------------------------------------
+----- Additional Variables -----------------
+--------------------------------------------
+
+ next(rtls_lo_f_d_delay) :=
+ case
+ next(start) = TRUE : undef; -- Assumed initialization
+ step = 8 & first8 & excess_OMS_propellant : 0;
+ TRUE : rtls_lo_f_d_delay;
+ esac;
+
+ next(wcb2) :=
+ case
+ next(start) = TRUE : undef; -- Assumed initialization
+ step = 10 & entry_mnvr_couter_LE_0 : post_sep_0;
+ step = 12 : case
+ r = reg4 : reg4_0;
+ TRUE : wcb2_3eo;
+ esac;
+ step = 14 & pre_sep : reg102_undef;
+ step = 15 : case
+ r = reg4 : reg4_0;
+ TRUE : wcb2_3eo;
+ esac;
+ step = 25 : reg2_neg4;
+ TRUE : wcb2;
+ esac;
+
+ next(q_gcb_i) :=
+ case
+ next(start) = TRUE : undef; -- Assumed initialization
+ step = 11 : quat_entry_M50_to_cmdbody;
+ step = 14 & pre_sep : quat_reg102_undef;
+ step = 16 : case
+ r = reg4 : quat_reg4;
+ TRUE : quat_reg3;
+ esac;
+ step = 22 : quat_reg2;
+
+-- Without this step the value "quat_reg2" would remain in "reg1":
+-- step = 23 & ABS_beta_n_GRT_beta_max & !high_rate_sep : undef;
+
+ TRUE : q_gcb_i;
+ esac;
+
+ next(oms_nz_lim) :=
+ case
+ next(start) = TRUE : undef; -- Assumed initialization
+ step = 9 & q_bar_a_LT_qbar_oms_dump & r != reg102 : oms_nz_lim_3eo;
+ step = 12 & mm602_OK : oms_nz_lim_std;
+ TRUE : oms_nz_lim;
+ esac;
+
+ next(contingency_nz_lim) :=
+ case
+ next(start) = TRUE : undef; -- Assumed initialization
+ step = 9 & q_bar_a_LT_qbar_oms_dump & r != reg102 :
+ contingency_nz_lim_3eo;
+ step = 12 & mm602_OK : contingency_nz_lim_std;
+ TRUE : contingency_nz_lim;
+ esac;
+
+DEFINE
+ finished := step = exit;
+ idle := step = undef;
+
+ start_cont_3eo_mode_select :=
+ case
+ step = 1 & !cont_3EO_start : TRUE;
+ TRUE : FALSE;
+ esac;
+
+ nextstep :=
+ case
+ step = 1 : a1;
+ step = a1 : case
+ (cont_3EO_start | mode_select_completed) : 2;
+ TRUE : step;
+ esac;
+ step = 2 : case
+ !cont_3EO_start : exit;
+ first3 : 3;
+ TRUE: 4;
+ esac;
+ step = 3 : 4;
+ step = 4 : case
+ et_sep_cmd : 7;
+ TRUE : 5;
+ esac;
+ step = 5 : case
+ h_dot_LT_0 & q_bar_a_GRT_qbar_max_sep &
+ m_mode != mm102 : exit;
+ TRUE : 6;
+ esac;
+ step = 6 :
+ case
+ r = reg102 : 13;
+ r in {reg3, reg4} : 15;
+ r = reg2 : 22;
+ r = reg1 : 27;
+ TRUE : exit;
+ esac;
+ step = 7 : case
+ cont_minus_z_compl : 8;
+ TRUE : exit;
+ esac;
+ step = 8 : case
+ excess_OMS_propellant & first8 : 9;
+ TRUE : 10;
+ esac;
+ step = 9 : exit;
+ step = 10 : case
+ !entry_mnvr_couter_LE_0 | rcs_all_jet_inhibit : exit;
+ TRUE : 11;
+ esac;
+ step = 11 : 12;
+ step = 12 : exit;
+ step = 13 : 14;
+ step = 14 : exit;
+ step = 15 : 16;
+ step = 16 : 17;
+ step = 17 : case
+ r = reg4 : 18;
+ TRUE : 20;
+ esac;
+ step = 18 : case
+ pch_cmd_reg4 | cond_18 : 19;
+ TRUE : exit;
+ esac;
+ step = 19 : exit;
+ step = 20 : case
+ ABS_alf_err_LT_alf_sep_err : b20;
+ TRUE : c20;
+ esac;
+ step = b20 : case
+ cond_20b : d20;
+ TRUE : exit;
+ esac;
+ step = c20 : case
+ alpha_ok : d20;
+ TRUE : 21;
+ esac;
+ step = d20 : exit;
+ TRUE : nextstep21;
+ esac;
+
+ nextstep21 :=
+ case
+ step = 21 : case
+ cond_21 : 15;
+ TRUE : exit;
+ esac;
+ step = 22 : 23;
+ step = 23 : case
+ ABS_beta_n_GRT_beta_max & !high_rate_sep : 27;
+ TRUE : 24;
+ esac;
+ step = 24 : case
+ cond_24 | high_rate_sep : 25;
+ TRUE : exit;
+ esac;
+ step = 25 : 26;
+ step = 26 : exit;
+ step = 27 : 28;
+ step = 28 : case
+ !et_sep_man_initiate : 29;
+ TRUE : exit;
+ esac;
+ step = 29 : exit;
+ start : 1;
+ step = exit : undef;
+ TRUE : step;
+ esac;
+
+ post_sep_mode := step in {7,8,9,10,11,12};
+
+------------------------------------------------------------------
+------------------------------------------------------------------
+
+MODULE main
+VAR
+ smode5: boolean;
+ vel : {GRT_vi_3eo_max, GRT_vi_3eo_min, LEQ_vi_3eo_min};
+ q_bar: {GRT_qbar_reg3, GRT_qbar_reg1, LEQ_qbar_reg1};
+ q_bar_a_GRT_qbar_max_sep : boolean;
+ q_bar_a_LT_qbar_oms_dump : boolean;
+ apogee_alt_LT_alt_ref : boolean;
+ h_dot_LT_hdot_reg2 : boolean;
+ h_dot_LT_0 : boolean;
+ alpha_n_GRT_alpha_reg2 : boolean;
+ delta_r_GRT_del_r_usp : boolean;
+ v_horiz_dnrng_LT_0: boolean;
+ meco_confirmed: boolean;
+ et_sep_cmd : boolean;
+ cont_minus_z_compl : boolean;
+ t_nav-t_et_sep_GRT_dt_min_z_102 : boolean;
+ ABS_q_orb_GRT_q_minus_z_max : boolean;
+ ABS_r_orb_GRT_r_minus_z_max : boolean;
+ excess_OMS_propellant : boolean;
+ entry_mnvr_couter_LE_0 : boolean;
+ rcs_all_jet_inhibit : boolean;
+ alt_GRT_alt_min_102_dump : boolean;
+ t_nav-t_gmtlo_LT_t_dmp_last : boolean;
+ pre_sep : boolean;
+ cond_18 : boolean;
+ q_orb_LT_0 : boolean;
+ ABS_alf_err_LT_alf_sep_err : boolean;
+ cond_20b : boolean;
+ cond_21 : boolean;
+ ABS_beta_n_GRT_beta_max : boolean;
+ cond_24 : boolean;
+ cond_26 : boolean;
+ cond_27 : boolean;
+ cond_29 : boolean;
+ mm602_OK : boolean;
+ start_guide : boolean;
+ mated_coast_mnvr : boolean;
+
+ cs: cont_3eo_mode_select(cg.start_cont_3eo_mode_select,
+ smode5,vel,q_bar,apogee_alt_LT_alt_ref,
+ h_dot_LT_hdot_reg2,alpha_n_GRT_alpha_reg2,
+ delta_r_GRT_del_r_usp,v_horiz_dnrng_LT_0,
+ cg.high_rate_sep,meco_confirmed);
+
+ cg: cont_3eo_guide(start_guide,
+ cs.cont_3EO_start, cs.region_selected, et_sep_cmd,
+ h_dot_LT_0, q_bar_a_GRT_qbar_max_sep, cs.m_mode, cs.r,
+ cont_minus_z_compl, t_nav-t_et_sep_GRT_dt_min_z_102,
+ ABS_q_orb_GRT_q_minus_z_max, ABS_r_orb_GRT_r_minus_z_max,
+ excess_OMS_propellant, q_bar_a_LT_qbar_oms_dump,
+ entry_mnvr_couter_LE_0, rcs_all_jet_inhibit,
+ alt_GRT_alt_min_102_dump, t_nav-t_gmtlo_LT_t_dmp_last,
+ pre_sep, cond_18, q_orb_LT_0, ABS_alf_err_LT_alf_sep_err,
+ cond_20b, cond_21, ABS_beta_n_GRT_beta_max, cond_24, cond_26,
+ cond_27, cond_29, mm602_OK);
+
+ASSIGN
+ init(start_guide) := FALSE;
+ init(mated_coast_mnvr) := FALSE;
+
+ next(entry_mnvr_couter_LE_0) :=
+ case
+ !entry_mnvr_couter_LE_0 : {FALSE, TRUE};
+ TRUE : TRUE;
+ esac;
+
+---------------------------------------------------------------------
+---------------------------------------------------------------------
+ next(start_guide) :=
+ case
+ start_guide : FALSE;
+ !cg.idle : FALSE;
+ TRUE : {FALSE, TRUE};
+ esac;
+
+ next(smode5) :=
+ case
+ fixed_values : smode5;
+ cg.idle : { FALSE, TRUE };
+ TRUE : smode5;
+ esac;
+
+ next(vel) :=
+ case
+ fixed_values : vel;
+ cg.idle : {GRT_vi_3eo_max, GRT_vi_3eo_min, LEQ_vi_3eo_min};
+ TRUE : vel;
+ esac;
+
+ next(q_bar) :=
+ case
+ fixed_values : q_bar;
+ cg.idle : {GRT_qbar_reg3, GRT_qbar_reg1, LEQ_qbar_reg1};
+ TRUE : q_bar;
+ esac;
+
+ next(q_bar_a_GRT_qbar_max_sep) :=
+ case
+ fixed_values : q_bar_a_GRT_qbar_max_sep;
+ cg.idle : { FALSE, TRUE };
+ TRUE : q_bar_a_GRT_qbar_max_sep;
+ esac;
+
+ next(apogee_alt_LT_alt_ref) :=
+ case
+ fixed_values : apogee_alt_LT_alt_ref;
+ cg.idle : { FALSE, TRUE };
+ TRUE : apogee_alt_LT_alt_ref;
+ esac;
+
+ next(h_dot_LT_hdot_reg2) :=
+ case
+ fixed_values : h_dot_LT_hdot_reg2;
+ cg.idle : { FALSE, TRUE };
+ TRUE : h_dot_LT_hdot_reg2;
+ esac;
+
+ next(h_dot_LT_0) :=
+ case
+ fixed_values : h_dot_LT_0;
+ cg.idle : { FALSE, TRUE };
+ TRUE : h_dot_LT_0;
+ esac;
+
+ next(alpha_n_GRT_alpha_reg2) :=
+ case
+ fixed_values : alpha_n_GRT_alpha_reg2;
+ cg.idle : { FALSE, TRUE };
+ TRUE : alpha_n_GRT_alpha_reg2;
+ esac;
+
+ next(delta_r_GRT_del_r_usp) :=
+ case
+ fixed_values : delta_r_GRT_del_r_usp;
+ cg.idle : { FALSE, TRUE };
+ TRUE : delta_r_GRT_del_r_usp;
+ esac;
+
+ next(v_horiz_dnrng_LT_0) :=
+ case
+ fixed_values : v_horiz_dnrng_LT_0;
+ cg.idle : { FALSE, TRUE };
+ TRUE : v_horiz_dnrng_LT_0;
+ esac;
+
+ next(meco_confirmed) :=
+ case
+ fixed_values : meco_confirmed;
+ meco_confirmed : TRUE;
+ cg.idle : { FALSE, TRUE };
+ TRUE : meco_confirmed;
+ esac;
+
+ next(et_sep_cmd) :=
+ case
+ fixed_values : et_sep_cmd;
+ et_sep_cmd : TRUE;
+ cg.idle : { FALSE, TRUE };
+ TRUE : et_sep_cmd;
+ esac;
+
+ next(cont_minus_z_compl) :=
+ case
+ fixed_values : cont_minus_z_compl;
+ cg.idle : { FALSE, TRUE };
+ TRUE : cont_minus_z_compl;
+ esac;
+
+ next(t_nav-t_et_sep_GRT_dt_min_z_102) :=
+ case
+ fixed_values : t_nav-t_et_sep_GRT_dt_min_z_102;
+ cg.idle : { FALSE, TRUE };
+ TRUE : t_nav-t_et_sep_GRT_dt_min_z_102;
+ esac;
+
+ next(ABS_q_orb_GRT_q_minus_z_max) :=
+ case
+ fixed_values : ABS_q_orb_GRT_q_minus_z_max;
+ cg.idle : { FALSE, TRUE };
+ TRUE : ABS_q_orb_GRT_q_minus_z_max;
+ esac;
+
+ next(ABS_r_orb_GRT_r_minus_z_max) :=
+ case
+ fixed_values : ABS_r_orb_GRT_r_minus_z_max;
+ cg.idle : { FALSE, TRUE };
+ TRUE : ABS_r_orb_GRT_r_minus_z_max;
+ esac;
+
+ next(excess_OMS_propellant) :=
+ case
+ fixed_values : excess_OMS_propellant;
+ cg.idle & excess_OMS_propellant : { FALSE, TRUE };
+ TRUE : excess_OMS_propellant;
+ esac;
+
+ next(q_bar_a_LT_qbar_oms_dump) :=
+ case
+ fixed_values : q_bar_a_LT_qbar_oms_dump;
+ cg.idle : { FALSE, TRUE };
+ TRUE : q_bar_a_LT_qbar_oms_dump;
+ esac;
+
+ next(rcs_all_jet_inhibit) :=
+ case
+ fixed_values : rcs_all_jet_inhibit;
+ cg.idle : { FALSE, TRUE };
+ TRUE : rcs_all_jet_inhibit;
+ esac;
+
+ next(alt_GRT_alt_min_102_dump) :=
+ case
+ fixed_values : alt_GRT_alt_min_102_dump;
+ cg.idle : { FALSE, TRUE };
+ TRUE : alt_GRT_alt_min_102_dump;
+ esac;
+
+ next(t_nav-t_gmtlo_LT_t_dmp_last) :=
+ case
+ fixed_values : t_nav-t_gmtlo_LT_t_dmp_last;
+ cg.idle : { FALSE, TRUE };
+ TRUE : t_nav-t_gmtlo_LT_t_dmp_last;
+ esac;
+
+ next(pre_sep) :=
+ case
+ fixed_values : pre_sep;
+ cg.idle : { FALSE, TRUE };
+ TRUE : pre_sep;
+ esac;
+
+ next(cond_18) :=
+ case
+ fixed_values : cond_18;
+ cg.idle : { FALSE, TRUE };
+ TRUE : cond_18;
+ esac;
+
+ next(q_orb_LT_0) :=
+ case
+ fixed_values : q_orb_LT_0;
+ cg.idle : { FALSE, TRUE };
+ TRUE : q_orb_LT_0;
+ esac;
+
+ next(ABS_alf_err_LT_alf_sep_err) :=
+ case
+ fixed_values : ABS_alf_err_LT_alf_sep_err;
+ cg.idle : { FALSE, TRUE };
+ TRUE : ABS_alf_err_LT_alf_sep_err;
+ esac;
+
+ next(cond_20b) :=
+ case
+ fixed_values : cond_20b;
+ cg.idle : { FALSE, TRUE };
+ TRUE : cond_20b;
+ esac;
+
+ next(cond_21) :=
+ case
+ fixed_values : cond_21;
+ cg.idle : { FALSE, TRUE };
+ TRUE : cond_21;
+ esac;
+
+ next(ABS_beta_n_GRT_beta_max) :=
+ case
+ fixed_values : ABS_beta_n_GRT_beta_max;
+ cg.idle : { FALSE, TRUE };
+ TRUE : ABS_beta_n_GRT_beta_max;
+ esac;
+
+ next(cond_24) :=
+ case
+ fixed_values : cond_24;
+ cg.idle : { FALSE, TRUE };
+ TRUE : cond_24;
+ esac;
+
+ next(cond_26) :=
+ case
+ fixed_values : cond_26;
+ cg.idle : { FALSE, TRUE };
+ TRUE : cond_26;
+ esac;
+
+ next(cond_27) :=
+ case
+ fixed_values : cond_27;
+ cg.idle : { FALSE, TRUE };
+ TRUE : cond_27;
+ esac;
+
+ next(cond_29) :=
+ case
+ fixed_values : cond_29;
+ cg.idle : { FALSE, TRUE };
+ TRUE : cond_29;
+ esac;
+
+ next(mm602_OK) :=
+ case
+ fixed_values : mm602_OK;
+ cg.idle : { FALSE, TRUE };
+ TRUE : mm602_OK;
+ esac;
+
+ next(mated_coast_mnvr) :=
+ case
+ next(cg.step) = 1 : FALSE;
+ cg.step = 6 & cg.r in {reg1, reg2, reg3, reg4, reg102} : TRUE;
+ TRUE : mated_coast_mnvr;
+ esac;
+
+---------------------------------------------------------------------
+---------------------------------------------------------------------
+DEFINE
+ fixed_values := FALSE;
+
+ output_ok :=
+ case
+ cg.q_gcb_i = undef | cg.wcb2 = undef |
+ cg.cont_3eo_pr_delay = 5 |
+ cg.etsep_y_drift = undef :
+ case
+ !mated_coast_mnvr: 1;
+ TRUE : undef;
+ esac;
+ !mated_coast_mnvr: toint(cg.q_gcb_i = quat_entry_M50_to_cmdbody &
+ cg.wcb2 = post_sep_0);
+-- reg1 never happens?
+-- cg.r = reg1 : (cg.q_gcb_i = quat_reg1 & cg.wcb2 = reg1_0 &
+-- cg.cont_3eo_pr_delay = minus_z_reg1 &
+-- cg.etsep_y_drift = minus_z_reg1) | cg.emerg_sep;
+ cg.r = reg2 : toint((cg.q_gcb_i = quat_reg2 & cg.wcb2 = reg2_neg4 &
+ cg.cont_3eo_pr_delay = minus_z_reg2 &
+ cg.etsep_y_drift = minus_z_reg2) | cg.emerg_sep);
+
+ cg.r = reg3 : toint((cg.q_gcb_i = quat_reg3 & cg.wcb2 = wcb2_3eo &
+ cg.cont_3eo_pr_delay = minus_z_reg3 &
+ cg.etsep_y_drift = minus_z_reg3) | cg.emerg_sep);
+ cg.r = reg4 : toint((cg.q_gcb_i = quat_reg4 & cg.wcb2 = reg4_0 &
+ cg.cont_3eo_pr_delay = minus_z_reg4 &
+ cg.etsep_y_drift = minus_z_reg4) | cg.emerg_sep);
+ cg.r = reg102 : toint((cg.q_gcb_i = quat_reg102_undef &
+ cg.wcb2 = reg102_undef &
+ cg.cont_3eo_pr_delay = minus_z_reg102 &
+ cg.etsep_y_drift = minus_z_reg102) | cg.emerg_sep);
+ TRUE : 0;
+ esac;
+
+---------------------------------------------------------------------
+-------- Specifications ---------------------------------------------
+---------------------------------------------------------------------
+
+-- Contingency Guide terminates
+
+SPEC AG(!cg.idle -> AF(cg.finished))
+
+-- Contingency guide can be executed infinitely often
+
+SPEC AG( (cg.idle | cg.finished) ->
+ EF(!(cg.idle | cg.finished) & EF(cg.finished)))
+
+-- Contingency mode select task works fine
+
+SPEC AG(cs.cont_3EO_start & cs.region_selected ->
+ ((cs.m_mode = mm102 | meco_confirmed) &
+ cs.r != reg-1 & cs.r != reg0))
+
+-- Bad (initial) value never happens again once region is computed
+-- unless we restart the task
+
+--SPEC AG(cs.r != reg-1 -> !E[!cg.start_cont_3eo_mode_select U
+-- cs.r = reg-1 & !cg.start_cont_3eo_mode_select])
+
+-- Comment out each of the regions and see if this is still true
+-- (Check, if ALL of the regions can happen)
+
+--SPEC AG(cs.r in {reg-1
+-- ,reg0
+-- ,reg1
+-- ,reg2
+-- ,reg3
+-- ,reg102
+-- })
+
+-- Comment out each of the regions and see if this is still true
+-- (Check, if ALL of the regions can happen)
+
+--SPEC AG(cg.r in {reg-1
+-- ,reg0
+-- ,reg1
+-- ,reg2
+-- ,reg3
+-- ,reg4
+-- ,reg102
+-- })
+
+-- Mode_select starts at the next step after its "start" bit is set:
+
+--SPEC AG(!cg.start_cont_3eo_mode_select ->
+-- AX(cg.start_cont_3eo_mode_select & cs.step in {exit, undef} ->
+-- AX(cs.step = 1 & !cs.region_selected)))
+
+-- During major mode 103, the inertial velocity is monitored.
+-- Below an I-loaded velocity, a MECO would constitute a contingency
+-- abort. (Must NOT be in SMODE=5 (??))
+
+SPEC AG(cg.start_cont_3eo_mode_select & cs.m_mode = mm103 &
+ vel = LEQ_vi_3eo_min & meco_confirmed & !smode5 ->
+ A[!cs.region_selected U cs.region_selected & cs.cont_3EO_start])
+
+-- Above a certain inertial velocity (in mode 103), the 3E/O field
+-- is blanked, indicating that a MECO at this point would not require
+-- an OPS 6 contingency abort.
+
+SPEC AG(cs.region_selected ->
+ (cs.m_mode = mm103 & vel = GRT_vi_3eo_max -> !cs.cont_3EO_start))
+
+-- Between the two velocities, an apogee altitude - velocity curve is
+-- constructed based on the current inertial velocity. If the apogee
+-- altitude is above this curve, a contingency abort capability is
+-- still required and a 3E/O region index will be calculated.
+-- Otherwise, the 3E/O field is blanked out and no further contingency
+-- abort calculations will be performed. (Must NOT be in SMODE=5 (??))
+
+SPEC AG(cg.start_cont_3eo_mode_select & cs.m_mode = mm103 &
+ vel = GRT_vi_3eo_min & meco_confirmed & !smode5 ->
+ A[!cs.region_selected U cs.region_selected &
+ apogee_alt_LT_alt_ref = !cs.cont_3EO_start])
+
+-- For an RTLS trajectory (SMODE=5), a check is made on the downrange
+-- velocity to see if the vehicle is heading away from the landing site.
+-- If this is the case, a 3E/O region index is calculated. If the vehicle
+-- is heading back to the landing site, and the current range to the MECO
+-- R-V line is greater than an I-loaded value, a 3E/O region index is
+-- calculated. Otherwise, an intact abort is possible and the 3E/O field
+-- is blanked.
+
+SPEC AG(cg.start_cont_3eo_mode_select & smode5 & meco_confirmed &
+ (!v_horiz_dnrng_LT_0 | !delta_r_GRT_del_r_usp) ->
+ A[!cs.region_selected U cs.region_selected & cs.cont_3EO_start])
+
+-- If this task is called prior to SRB separation [mm102], the 3E/O region
+-- index is set to 102 and the 3E/O contingency flag is set.
+
+SPEC AG(cs.m_mode = mm102 & cg.start_cont_3eo_mode_select ->
+ AX (A [ !cs.region_selected U cs.region_selected &
+ cs.r = reg102 & cs.cont_3EO_start]))
+
+-- After SRB separation, on every pass that the 3E/O region index is
+-- calculated, a check is made to see if MECO confirmed has occured. If
+-- so, a check is made to see if the major mode is 103. If so, an RTLS is
+-- automatically invoked to transition to major mode 601.
+
+SPEC AG(!cs.region_selected & cs.m_mode = mm103 & meco_confirmed ->
+ A[!cs.region_selected U cs.region_selected & cs.r != reg0 ->
+ cs.m_mode = mm601 & cs.RTLS_abort_declared])
+
+-- Once the 3E/O contingency flag has been set, this task is no longer
+-- executed.
+
+SPEC AG(cs.cont_3EO_start -> AG(!cg.start_cont_3eo_mode_select))
+
+-- If MECO confirmed occurs in MM103 and an OPS 6 contingency abort
+-- procedure is still required, contingency 3E/O guidance sets the
+-- CONT_3EO_START flag ON. Contingency 3E/O guidance then switches
+-- from its display support function into an actual auto guidance
+-- steering process. [...] Contingency 3E/O guidance sets the RTLS abort
+-- declared flag and the MSC performs the transition from from major mode
+-- 103 to 601.
+
+SPEC AG(!cg.idle & !cg.finished & !cs.region_selected & cs.m_mode = mm103 ->
+ A[ !cg.finished U cg.finished & cs.region_selected &
+ (cs.cont_3EO_start -> cs.m_mode = mm601 & cs.RTLS_abort_declared) ])
+
+-- If MECO confirmed occurs in a major mode 601 and a contingency abort
+-- procedure is still required, contingency 3E/O guidance sets the
+-- CONT_3EO_START flag ON. [...] Contingency 3E/O guidance then commands
+-- 3E/O auto maneuvers in major mode 601. [What are these maneuvers??]
+
+SPEC AG(cg.finished & cs.m_mode = mm601 & !et_sep_cmd &
+ meco_confirmed & cs.cont_3EO_start ->
+ cg.q_gcb_i in {quat_reg1, quat_reg2, quat_reg3, quat_reg4, undef}
+ | cg.emerg_sep)
+
+-- If MECO confirmed occurs in a first stage (MM102) [...], contingency
+-- 3E/O guidance will command a fast ET separation during SRB tailoff in
+-- major mode 102. CONT 3E/O GUID will then command maneuver post-sep in
+-- MM601 (???). [ I'm not sure what indicates fast ET sep.: emerg_sep or
+-- early_sep, or what? ]
+
+SPEC AG(cg.finished & cs.m_mode = mm102 & meco_confirmed & pre_sep ->
+ cg.emerg_sep | et_sep_cmd
+ | cg.et_sep_man_initiate
+ | cg.early_sep
+ )
+
+---------------------------------------------
+-- Invariants from Murphi code --------------
+---------------------------------------------
+
+--SPEC AG(cg.finished -> (output_ok != 0 | (output_ok = undef &
+-- (cg.emerg_sep | !cg.cont_sep_cplt))))
+
+--SPEC AG(!cg.finished & !cg.idle -> !mated_coast_mnvr | !et_sep_cmd)
+
+-- Stronger version !!!
+
+SPEC AG(cg.finished -> output_ok != 0)
+
+-- Contingency Guidance shall command an ET separation
+-- [under certain conditions :-].
+
+SPEC AG(cs.cont_3EO_start & cg.finished &
+ (cg.r = reg1 -> cond_29) &
+ (cg.r = reg2 -> cond_24 & cond_26) &
+ (cg.r = reg3 -> cg.alpha_ok &
+ (ABS_alf_err_LT_alf_sep_err -> cond_20b)) &
+ (cg.r = reg4 -> cond_18 & q_orb_LT_0) &
+ (cg.r = reg102 -> pre_sep) ->
+ et_sep_cmd | cg.et_sep_man_initiate
+ | cg.early_sep
+ | cg.emerg_sep
+ )
+
+-- Contingency Guidance shall command at most one interconnected OMS dump.
+
+SPEC AG(cg.finished & cg.oms_rcs_i_c_inh_ena_cmd ->
+ AG(!cg.oms_rcs_i_c_inh_ena_cmd -> AG(!cg.oms_rcs_i_c_inh_ena_cmd)))
+
+-- Contingency Guidance shall command a transition to glide RTLS
+-- (flight mode 602)
+
+SPEC AG(cg.finished & cs.m_mode = mm601 ->
+ --cg.cont_sep_cplt | cg.emerg_sep |
+ cg.call_RTLS_abort_task)
+
+-- Paper, p. 28, unstated assumption 2: at step 6 the region is
+-- among 102, 1-4.
+
+SPEC AG(cg.step = 6 -> cg.r in {reg102, reg1, reg2, reg3, reg4})
+
+-- The transition to mode 602 shall not occur until the entry maneuver
+-- has been calculated
+
+SPEC !E[cg.q_gcb_i = undef U cg.cont_sep_cplt & cg.q_gcb_i = undef]
+
+-- The entry maneuver calculations shall not commence until the OMS/RCS
+-- interconnect, if any, is complete (??? What does it exactly mean???)
+-- !!!
+--SPEC AG(cg.oms_rcs_i_c_inh_ena_cmd ->
+-- !E[cg.oms_rcs_i_c_inh_ena_cmd U
+-- cg.q_gcb_i != undef & cg.oms_rcs_i_c_inh_ena_cmd])
+
+SPEC AG(cg.oms_rcs_i_c_inh_ena_cmd ->
+ !E[rcs_all_jet_inhibit U
+ cg.q_gcb_i != undef & rcs_all_jet_inhibit])
+
+-- The OMS dump shall not be considered until the -Z translation is complete.
+
+SPEC !E[!cont_minus_z_compl & cg.r != reg102 U cg.orbiter_dump_ena]
+
+-- Completion of -Z translation shall not be checked until ET separation
+-- has been commanded
+
+SPEC !E[!et_sep_cmd U cg.step = 7]
+
+-- ET separation shall be commanded if and only if an abort maneuver
+-- region is assigned [and again there are *certain conditions*].
+
+SPEC AG(cg.finished & cs.cont_3EO_start &
+ (cg.r = reg1 -> cond_29) &
+ (cg.r = reg2 -> cond_24 & cond_26) &
+ (cg.r = reg3 -> cg.alpha_ok &
+ (ABS_alf_err_LT_alf_sep_err -> cond_20b)) &
+ (cg.r = reg4 -> cond_18 & q_orb_LT_0) &
+ (cg.r = reg102 -> pre_sep) ->
+ (cg.et_sep_man_initiate | et_sep_cmd
+ <-> cg.r in {reg1, reg2, reg3, reg4, reg102}))
+
+-- The assigned region can not change arbitrarily.
+
+-- Regions 1 and 2 may interchange, but will not switch to any other region:
+
+SPEC AG(cg.finished & cs.cont_3EO_start & cg.r in {reg1,reg2} ->
+ AG(cg.finished -> cg.r in {reg1,reg2}))
+
+-- Regions 3 and 4 may interchange, but will not switch to any other region:
+
+SPEC AG(cg.finished & cs.cont_3EO_start & cg.r in {reg3,reg4} ->
+ AG(cg.finished -> cg.r in {reg3,reg4}))
+
+-- Region 102 never changes:
+
+SPEC AG(cg.finished & cg.r = reg102 -> AG(cg.finished -> cg.r = reg102))
diff --git a/tests/examplefiles/hello-world.puzzlet.aheui b/tests/examplefiles/hello-world.puzzlet.aheui
new file mode 100644
index 00000000..e7ef3a62
--- /dev/null
+++ b/tests/examplefiles/hello-world.puzzlet.aheui
@@ -0,0 +1,10 @@
+밤밣따빠밣밟따뿌
+빠맣파빨받밤뚜뭏
+돋밬탕빠맣붏두붇
+볻뫃박발뚷투뭏붖
+뫃도뫃희멓뭏뭏붘
+뫃봌토범더벌뿌뚜
+뽑뽀멓멓더벓뻐뚠
+뽀덩벐멓뻐덕더벅
+
+https://github.com/aheui/snippets/blob/master/hello-world/hello-world.puzzlet.aheui
diff --git a/tests/examplefiles/plain.bst b/tests/examplefiles/plain.bst
new file mode 100644
index 00000000..7adf4bb0
--- /dev/null
+++ b/tests/examplefiles/plain.bst
@@ -0,0 +1,1097 @@
+% BibTeX standard bibliography style `plain'
+ % Version 0.99b (8-Dec-10 release) for BibTeX versions 0.99a or later.
+ % Copyright (C) 1984, 1985, 1988, 2010 Howard Trickey and Oren Patashnik.
+ % Unlimited copying and redistribution of this file are permitted as long as
+ % it is unmodified. Modifications (and redistribution of modified versions)
+ % are also permitted, but only if the resulting file is renamed to something
+ % besides btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst.
+ % This restriction helps ensure that all standard styles are identical.
+ % The file btxbst.doc has the documentation for this style.
+
+ENTRY
+ { address
+ author
+ booktitle
+ chapter
+ edition
+ editor
+ howpublished
+ institution
+ journal
+ key
+ month
+ note
+ number
+ organization
+ pages
+ publisher
+ school
+ series
+ title
+ type
+ volume
+ year
+ }
+ {}
+ { label }
+
+INTEGERS { output.state before.all mid.sentence after.sentence after.block }
+
+FUNCTION {init.state.consts}
+{ #0 'before.all :=
+ #1 'mid.sentence :=
+ #2 'after.sentence :=
+ #3 'after.block :=
+}
+
+STRINGS { s t }
+
+FUNCTION {output.nonnull}
+{ 's :=
+ output.state mid.sentence =
+ { ", " * write$ }
+ { output.state after.block =
+ { add.period$ write$
+ newline$
+ "\newblock " write$
+ }
+ { output.state before.all =
+ 'write$
+ { add.period$ " " * write$ }
+ if$
+ }
+ if$
+ mid.sentence 'output.state :=
+ }
+ if$
+ s
+}
+
+FUNCTION {output}
+{ duplicate$ empty$
+ 'pop$
+ 'output.nonnull
+ if$
+}
+
+FUNCTION {output.check}
+{ 't :=
+ duplicate$ empty$
+ { pop$ "empty " t * " in " * cite$ * warning$ }
+ 'output.nonnull
+ if$
+}
+
+FUNCTION {output.bibitem}
+{ newline$
+ "\bibitem{" write$
+ cite$ write$
+ "}" write$
+ newline$
+ ""
+ before.all 'output.state :=
+}
+
+FUNCTION {fin.entry}
+{ add.period$
+ write$
+ newline$
+}
+
+FUNCTION {new.block}
+{ output.state before.all =
+ 'skip$
+ { after.block 'output.state := }
+ if$
+}
+
+FUNCTION {new.sentence}
+{ output.state after.block =
+ 'skip$
+ { output.state before.all =
+ 'skip$
+ { after.sentence 'output.state := }
+ if$
+ }
+ if$
+}
+
+FUNCTION {not}
+{ { #0 }
+ { #1 }
+ if$
+}
+
+FUNCTION {and}
+{ 'skip$
+ { pop$ #0 }
+ if$
+}
+
+FUNCTION {or}
+{ { pop$ #1 }
+ 'skip$
+ if$
+}
+
+FUNCTION {new.block.checka}
+{ empty$
+ 'skip$
+ 'new.block
+ if$
+}
+
+FUNCTION {new.block.checkb}
+{ empty$
+ swap$ empty$
+ and
+ 'skip$
+ 'new.block
+ if$
+}
+
+FUNCTION {new.sentence.checka}
+{ empty$
+ 'skip$
+ 'new.sentence
+ if$
+}
+
+FUNCTION {new.sentence.checkb}
+{ empty$
+ swap$ empty$
+ and
+ 'skip$
+ 'new.sentence
+ if$
+}
+
+FUNCTION {field.or.null}
+{ duplicate$ empty$
+ { pop$ "" }
+ 'skip$
+ if$
+}
+
+FUNCTION {emphasize}
+{ duplicate$ empty$
+ { pop$ "" }
+ { "{\em " swap$ * "}" * }
+ if$
+}
+
+INTEGERS { nameptr namesleft numnames }
+
+FUNCTION {format.names}
+{ 's :=
+ #1 'nameptr :=
+ s num.names$ 'numnames :=
+ numnames 'namesleft :=
+ { namesleft #0 > }
+ { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't :=
+ nameptr #1 >
+ { namesleft #1 >
+ { ", " * t * }
+ { numnames #2 >
+ { "," * }
+ 'skip$
+ if$
+ t "others" =
+ { " et~al." * }
+ { " and " * t * }
+ if$
+ }
+ if$
+ }
+ 't
+ if$
+ nameptr #1 + 'nameptr :=
+ namesleft #1 - 'namesleft :=
+ }
+ while$
+}
+
+FUNCTION {format.authors}
+{ author empty$
+ { "" }
+ { author format.names }
+ if$
+}
+
+FUNCTION {format.editors}
+{ editor empty$
+ { "" }
+ { editor format.names
+ editor num.names$ #1 >
+ { ", editors" * }
+ { ", editor" * }
+ if$
+ }
+ if$
+}
+
+FUNCTION {format.title}
+{ title empty$
+ { "" }
+ { title "t" change.case$ }
+ if$
+}
+
+FUNCTION {n.dashify}
+{ 't :=
+ ""
+ { t empty$ not }
+ { t #1 #1 substring$ "-" =
+ { t #1 #2 substring$ "--" = not
+ { "--" *
+ t #2 global.max$ substring$ 't :=
+ }
+ { { t #1 #1 substring$ "-" = }
+ { "-" *
+ t #2 global.max$ substring$ 't :=
+ }
+ while$
+ }
+ if$
+ }
+ { t #1 #1 substring$ *
+ t #2 global.max$ substring$ 't :=
+ }
+ if$
+ }
+ while$
+}
+
+FUNCTION {format.date}
+{ year empty$
+ { month empty$
+ { "" }
+ { "there's a month but no year in " cite$ * warning$
+ month
+ }
+ if$
+ }
+ { month empty$
+ 'year
+ { month " " * year * }
+ if$
+ }
+ if$
+}
+
+FUNCTION {format.btitle}
+{ title emphasize
+}
+
+FUNCTION {tie.or.space.connect}
+{ duplicate$ text.length$ #3 <
+ { "~" }
+ { " " }
+ if$
+ swap$ * *
+}
+
+FUNCTION {either.or.check}
+{ empty$
+ 'pop$
+ { "can't use both " swap$ * " fields in " * cite$ * warning$ }
+ if$
+}
+
+FUNCTION {format.bvolume}
+{ volume empty$
+ { "" }
+ { "volume" volume tie.or.space.connect
+ series empty$
+ 'skip$
+ { " of " * series emphasize * }
+ if$
+ "volume and number" number either.or.check
+ }
+ if$
+}
+
+FUNCTION {format.number.series}
+{ volume empty$
+ { number empty$
+ { series field.or.null }
+ { output.state mid.sentence =
+ { "number" }
+ { "Number" }
+ if$
+ number tie.or.space.connect
+ series empty$
+ { "there's a number but no series in " cite$ * warning$ }
+ { " in " * series * }
+ if$
+ }
+ if$
+ }
+ { "" }
+ if$
+}
+
+FUNCTION {format.edition}
+{ edition empty$
+ { "" }
+ { output.state mid.sentence =
+ { edition "l" change.case$ " edition" * }
+ { edition "t" change.case$ " edition" * }
+ if$
+ }
+ if$
+}
+
+INTEGERS { multiresult }
+
+FUNCTION {multi.page.check}
+{ 't :=
+ #0 'multiresult :=
+ { multiresult not
+ t empty$ not
+ and
+ }
+ { t #1 #1 substring$
+ duplicate$ "-" =
+ swap$ duplicate$ "," =
+ swap$ "+" =
+ or or
+ { #1 'multiresult := }
+ { t #2 global.max$ substring$ 't := }
+ if$
+ }
+ while$
+ multiresult
+}
+
+FUNCTION {format.pages}
+{ pages empty$
+ { "" }
+ { pages multi.page.check
+ { "pages" pages n.dashify tie.or.space.connect }
+ { "page" pages tie.or.space.connect }
+ if$
+ }
+ if$
+}
+
+FUNCTION {format.vol.num.pages}
+{ volume field.or.null
+ number empty$
+ 'skip$
+ { "(" number * ")" * *
+ volume empty$
+ { "there's a number but no volume in " cite$ * warning$ }
+ 'skip$
+ if$
+ }
+ if$
+ pages empty$
+ 'skip$
+ { duplicate$ empty$
+ { pop$ format.pages }
+ { ":" * pages n.dashify * }
+ if$
+ }
+ if$
+}
+
+FUNCTION {format.chapter.pages}
+{ chapter empty$
+ 'format.pages
+ { type empty$
+ { "chapter" }
+ { type "l" change.case$ }
+ if$
+ chapter tie.or.space.connect
+ pages empty$
+ 'skip$
+ { ", " * format.pages * }
+ if$
+ }
+ if$
+}
+
+FUNCTION {format.in.ed.booktitle}
+{ booktitle empty$
+ { "" }
+ { editor empty$
+ { "In " booktitle emphasize * }
+ { "In " format.editors * ", " * booktitle emphasize * }
+ if$
+ }
+ if$
+}
+
+FUNCTION {empty.misc.check}
+{ author empty$ title empty$ howpublished empty$
+ month empty$ year empty$ note empty$
+ and and and and and
+ key empty$ not and
+ { "all relevant fields are empty in " cite$ * warning$ }
+ 'skip$
+ if$
+}
+
+FUNCTION {format.thesis.type}
+{ type empty$
+ 'skip$
+ { pop$
+ type "t" change.case$
+ }
+ if$
+}
+
+FUNCTION {format.tr.number}
+{ type empty$
+ { "Technical Report" }
+ 'type
+ if$
+ number empty$
+ { "t" change.case$ }
+ { number tie.or.space.connect }
+ if$
+}
+
+FUNCTION {format.article.crossref}
+{ key empty$
+ { journal empty$
+ { "need key or journal for " cite$ * " to crossref " * crossref *
+ warning$
+ ""
+ }
+ { "In {\em " journal * "\/}" * }
+ if$
+ }
+ { "In " key * }
+ if$
+ " \cite{" * crossref * "}" *
+}
+
+FUNCTION {format.crossref.editor}
+{ editor #1 "{vv~}{ll}" format.name$
+ editor num.names$ duplicate$
+ #2 >
+ { pop$ " et~al." * }
+ { #2 <
+ 'skip$
+ { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" =
+ { " et~al." * }
+ { " and " * editor #2 "{vv~}{ll}" format.name$ * }
+ if$
+ }
+ if$
+ }
+ if$
+}
+
+FUNCTION {format.book.crossref}
+{ volume empty$
+ { "empty volume in " cite$ * "'s crossref of " * crossref * warning$
+ "In "
+ }
+ { "Volume" volume tie.or.space.connect
+ " of " *
+ }
+ if$
+ editor empty$
+ editor field.or.null author field.or.null =
+ or
+ { key empty$
+ { series empty$
+ { "need editor, key, or series for " cite$ * " to crossref " *
+ crossref * warning$
+ "" *
+ }
+ { "{\em " * series * "\/}" * }
+ if$
+ }
+ { key * }
+ if$
+ }
+ { format.crossref.editor * }
+ if$
+ " \cite{" * crossref * "}" *
+}
+
+FUNCTION {format.incoll.inproc.crossref}
+{ editor empty$
+ editor field.or.null author field.or.null =
+ or
+ { key empty$
+ { booktitle empty$
+ { "need editor, key, or booktitle for " cite$ * " to crossref " *
+ crossref * warning$
+ ""
+ }
+ { "In {\em " booktitle * "\/}" * }
+ if$
+ }
+ { "In " key * }
+ if$
+ }
+ { "In " format.crossref.editor * }
+ if$
+ " \cite{" * crossref * "}" *
+}
+
+FUNCTION {article}
+{ output.bibitem
+ format.authors "author" output.check
+ new.block
+ format.title "title" output.check
+ new.block
+ crossref missing$
+ { journal emphasize "journal" output.check
+ format.vol.num.pages output
+ format.date "year" output.check
+ }
+ { format.article.crossref output.nonnull
+ format.pages output
+ }
+ if$
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {book}
+{ output.bibitem
+ author empty$
+ { format.editors "author and editor" output.check }
+ { format.authors output.nonnull
+ crossref missing$
+ { "author and editor" editor either.or.check }
+ 'skip$
+ if$
+ }
+ if$
+ new.block
+ format.btitle "title" output.check
+ crossref missing$
+ { format.bvolume output
+ new.block
+ format.number.series output
+ new.sentence
+ publisher "publisher" output.check
+ address output
+ }
+ { new.block
+ format.book.crossref output.nonnull
+ }
+ if$
+ format.edition output
+ format.date "year" output.check
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {booklet}
+{ output.bibitem
+ format.authors output
+ new.block
+ format.title "title" output.check
+ howpublished address new.block.checkb
+ howpublished output
+ address output
+ format.date output
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {inbook}
+{ output.bibitem
+ author empty$
+ { format.editors "author and editor" output.check }
+ { format.authors output.nonnull
+ crossref missing$
+ { "author and editor" editor either.or.check }
+ 'skip$
+ if$
+ }
+ if$
+ new.block
+ format.btitle "title" output.check
+ crossref missing$
+ { format.bvolume output
+ format.chapter.pages "chapter and pages" output.check
+ new.block
+ format.number.series output
+ new.sentence
+ publisher "publisher" output.check
+ address output
+ }
+ { format.chapter.pages "chapter and pages" output.check
+ new.block
+ format.book.crossref output.nonnull
+ }
+ if$
+ format.edition output
+ format.date "year" output.check
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {incollection}
+{ output.bibitem
+ format.authors "author" output.check
+ new.block
+ format.title "title" output.check
+ new.block
+ crossref missing$
+ { format.in.ed.booktitle "booktitle" output.check
+ format.bvolume output
+ format.number.series output
+ format.chapter.pages output
+ new.sentence
+ publisher "publisher" output.check
+ address output
+ format.edition output
+ format.date "year" output.check
+ }
+ { format.incoll.inproc.crossref output.nonnull
+ format.chapter.pages output
+ }
+ if$
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {inproceedings}
+{ output.bibitem
+ format.authors "author" output.check
+ new.block
+ format.title "title" output.check
+ new.block
+ crossref missing$
+ { format.in.ed.booktitle "booktitle" output.check
+ format.bvolume output
+ format.number.series output
+ format.pages output
+ address empty$
+ { organization publisher new.sentence.checkb
+ organization output
+ publisher output
+ format.date "year" output.check
+ }
+ { address output.nonnull
+ format.date "year" output.check
+ new.sentence
+ organization output
+ publisher output
+ }
+ if$
+ }
+ { format.incoll.inproc.crossref output.nonnull
+ format.pages output
+ }
+ if$
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {conference} { inproceedings }
+
+FUNCTION {manual}
+{ output.bibitem
+ author empty$
+ { organization empty$
+ 'skip$
+ { organization output.nonnull
+ address output
+ }
+ if$
+ }
+ { format.authors output.nonnull }
+ if$
+ new.block
+ format.btitle "title" output.check
+ author empty$
+ { organization empty$
+ { address new.block.checka
+ address output
+ }
+ 'skip$
+ if$
+ }
+ { organization address new.block.checkb
+ organization output
+ address output
+ }
+ if$
+ format.edition output
+ format.date output
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {mastersthesis}
+{ output.bibitem
+ format.authors "author" output.check
+ new.block
+ format.title "title" output.check
+ new.block
+ "Master's thesis" format.thesis.type output.nonnull
+ school "school" output.check
+ address output
+ format.date "year" output.check
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {misc}
+{ output.bibitem
+ format.authors output
+ title howpublished new.block.checkb
+ format.title output
+ howpublished new.block.checka
+ howpublished output
+ format.date output
+ new.block
+ note output
+ fin.entry
+ empty.misc.check
+}
+
+FUNCTION {phdthesis}
+{ output.bibitem
+ format.authors "author" output.check
+ new.block
+ format.btitle "title" output.check
+ new.block
+ "PhD thesis" format.thesis.type output.nonnull
+ school "school" output.check
+ address output
+ format.date "year" output.check
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {proceedings}
+{ output.bibitem
+ editor empty$
+ { organization output }
+ { format.editors output.nonnull }
+ if$
+ new.block
+ format.btitle "title" output.check
+ format.bvolume output
+ format.number.series output
+ address empty$
+ { editor empty$
+ { publisher new.sentence.checka }
+ { organization publisher new.sentence.checkb
+ organization output
+ }
+ if$
+ publisher output
+ format.date "year" output.check
+ }
+ { address output.nonnull
+ format.date "year" output.check
+ new.sentence
+ editor empty$
+ 'skip$
+ { organization output }
+ if$
+ publisher output
+ }
+ if$
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {techreport}
+{ output.bibitem
+ format.authors "author" output.check
+ new.block
+ format.title "title" output.check
+ new.block
+ format.tr.number output.nonnull
+ institution "institution" output.check
+ address output
+ format.date "year" output.check
+ new.block
+ note output
+ fin.entry
+}
+
+FUNCTION {unpublished}
+{ output.bibitem
+ format.authors "author" output.check
+ new.block
+ format.title "title" output.check
+ new.block
+ note "note" output.check
+ format.date output
+ fin.entry
+}
+
+FUNCTION {default.type} { misc }
+
+MACRO {jan} {"January"}
+
+MACRO {feb} {"February"}
+
+MACRO {mar} {"March"}
+
+MACRO {apr} {"April"}
+
+MACRO {may} {"May"}
+
+MACRO {jun} {"June"}
+
+MACRO {jul} {"July"}
+
+MACRO {aug} {"August"}
+
+MACRO {sep} {"September"}
+
+MACRO {oct} {"October"}
+
+MACRO {nov} {"November"}
+
+MACRO {dec} {"December"}
+
+MACRO {acmcs} {"ACM Computing Surveys"}
+
+MACRO {acta} {"Acta Informatica"}
+
+MACRO {cacm} {"Communications of the ACM"}
+
+MACRO {ibmjrd} {"IBM Journal of Research and Development"}
+
+MACRO {ibmsj} {"IBM Systems Journal"}
+
+MACRO {ieeese} {"IEEE Transactions on Software Engineering"}
+
+MACRO {ieeetc} {"IEEE Transactions on Computers"}
+
+MACRO {ieeetcad}
+ {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"}
+
+MACRO {ipl} {"Information Processing Letters"}
+
+MACRO {jacm} {"Journal of the ACM"}
+
+MACRO {jcss} {"Journal of Computer and System Sciences"}
+
+MACRO {scp} {"Science of Computer Programming"}
+
+MACRO {sicomp} {"SIAM Journal on Computing"}
+
+MACRO {tocs} {"ACM Transactions on Computer Systems"}
+
+MACRO {tods} {"ACM Transactions on Database Systems"}
+
+MACRO {tog} {"ACM Transactions on Graphics"}
+
+MACRO {toms} {"ACM Transactions on Mathematical Software"}
+
+MACRO {toois} {"ACM Transactions on Office Information Systems"}
+
+MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"}
+
+MACRO {tcs} {"Theoretical Computer Science"}
+
+READ
+
+FUNCTION {sortify}
+{ purify$
+ "l" change.case$
+}
+
+INTEGERS { len }
+
+FUNCTION {chop.word}
+{ 's :=
+ 'len :=
+ s #1 len substring$ =
+ { s len #1 + global.max$ substring$ }
+ 's
+ if$
+}
+
+FUNCTION {sort.format.names}
+{ 's :=
+ #1 'nameptr :=
+ ""
+ s num.names$ 'numnames :=
+ numnames 'namesleft :=
+ { namesleft #0 > }
+ { nameptr #1 >
+ { " " * }
+ 'skip$
+ if$
+ s nameptr "{vv{ } }{ll{ }}{ ff{ }}{ jj{ }}" format.name$ 't :=
+ nameptr numnames = t "others" = and
+ { "et al" * }
+ { t sortify * }
+ if$
+ nameptr #1 + 'nameptr :=
+ namesleft #1 - 'namesleft :=
+ }
+ while$
+}
+
+FUNCTION {sort.format.title}
+{ 't :=
+ "A " #2
+ "An " #3
+ "The " #4 t chop.word
+ chop.word
+ chop.word
+ sortify
+ #1 global.max$ substring$
+}
+
+FUNCTION {author.sort}
+{ author empty$
+ { key empty$
+ { "to sort, need author or key in " cite$ * warning$
+ ""
+ }
+ { key sortify }
+ if$
+ }
+ { author sort.format.names }
+ if$
+}
+
+FUNCTION {author.editor.sort}
+{ author empty$
+ { editor empty$
+ { key empty$
+ { "to sort, need author, editor, or key in " cite$ * warning$
+ ""
+ }
+ { key sortify }
+ if$
+ }
+ { editor sort.format.names }
+ if$
+ }
+ { author sort.format.names }
+ if$
+}
+
+FUNCTION {author.organization.sort}
+{ author empty$
+ { organization empty$
+ { key empty$
+ { "to sort, need author, organization, or key in " cite$ * warning$
+ ""
+ }
+ { key sortify }
+ if$
+ }
+ { "The " #4 organization chop.word sortify }
+ if$
+ }
+ { author sort.format.names }
+ if$
+}
+
+FUNCTION {editor.organization.sort}
+{ editor empty$
+ { organization empty$
+ { key empty$
+ { "to sort, need editor, organization, or key in " cite$ * warning$
+ ""
+ }
+ { key sortify }
+ if$
+ }
+ { "The " #4 organization chop.word sortify }
+ if$
+ }
+ { editor sort.format.names }
+ if$
+}
+
+FUNCTION {presort}
+{ type$ "book" =
+ type$ "inbook" =
+ or
+ 'author.editor.sort
+ { type$ "proceedings" =
+ 'editor.organization.sort
+ { type$ "manual" =
+ 'author.organization.sort
+ 'author.sort
+ if$
+ }
+ if$
+ }
+ if$
+ " "
+ *
+ year field.or.null sortify
+ *
+ " "
+ *
+ title field.or.null
+ sort.format.title
+ *
+ #1 entry.max$ substring$
+ 'sort.key$ :=
+}
+
+ITERATE {presort}
+
+SORT
+
+STRINGS { longest.label }
+
+INTEGERS { number.label longest.label.width }
+
+FUNCTION {initialize.longest.label}
+{ "" 'longest.label :=
+ #1 'number.label :=
+ #0 'longest.label.width :=
+}
+
+FUNCTION {longest.label.pass}
+{ number.label int.to.str$ 'label :=
+ number.label #1 + 'number.label :=
+ label width$ longest.label.width >
+ { label 'longest.label :=
+ label width$ 'longest.label.width :=
+ }
+ 'skip$
+ if$
+}
+
+EXECUTE {initialize.longest.label}
+
+ITERATE {longest.label.pass}
+
+FUNCTION {begin.bib}
+{ preamble$ empty$
+ 'skip$
+ { preamble$ write$ newline$ }
+ if$
+ "\begin{thebibliography}{" longest.label * "}" * write$ newline$
+}
+
+EXECUTE {begin.bib}
+
+EXECUTE {init.state.consts}
+
+ITERATE {call.type$}
+
+FUNCTION {end.bib}
+{ newline$
+ "\end{thebibliography}" write$ newline$
+}
+
+EXECUTE {end.bib}
diff --git a/tests/examplefiles/test.bib b/tests/examplefiles/test.bib
new file mode 100644
index 00000000..87e558d8
--- /dev/null
+++ b/tests/examplefiles/test.bib
@@ -0,0 +1,77 @@
+This is an example BibTeX file.
+This text is a comment.
+
+@preamble{"%%% example BibTeX file"}
+
+@Preamble{"\newcommand{\noopsort}[1]{} "
+ "\newcommand{\noopsort}[1]{} "}
+
+@String{SCI = "Science"}
+
+@STRING{JFernandez = "Fernandez, Julio M."}
+@StRiNg{HGaub = "Gaub, Hermann E."}
+@string{MGautel = "Gautel, Mathias"}
+@String{FOesterhelt = "Oesterhelt, Filipp"}
+@String{MRief = "Rief, Matthias"}
+
+@Article{rief97b,
+ author = MRief #" and "# MGautel #" and "# FOesterhelt
+ #" and "# JFernandez #" and "# HGaub,
+ title = "Reversible Unfolding of Individual Titin
+ Immunoglobulin Domains by {AFM}",
+ journal = SCI,
+ volume = 276,
+ number = 5315,
+ pages = "1109--1112",
+ year = 1997,
+ doi = "10.1126/science.276.5315.1109",
+ URL = "http://www.sciencemag.org/cgi/content/abstract/276/5315/1109",
+ eprint = "http://www.sciencemag.org/cgi/reprint/276/5315/1109.pdf",
+}
+
+
+Parens can be used instead of braces:
+
+@ARTICLE(ruckenstein-diffusion,
+ author = "Liu, Hongquin and Ruckenstein, Eli",
+ language = "english",
+ title = "Predicting the Diffusion Coefficient in Supercritical Fluids",
+ journal = "Ind. Eng. Chem. Res.",
+ volume = "36",
+ year = "1997",
+ pages = "888-895"
+)
+
+@book{
+ viktorov-methods,
+ author = "Викторов, Михаил Маркович",
+ publisher = "Л.: <<Химия>>",
+ title = "Методы вычисления физико-химических величин и прикладные расчёты",
+ language = "russian",
+ year = "1977",
+ isbn = "000-0000000000",
+}
+
+@comment{jackson-commented-out,
+ author = "Jackson, P\'eter",
+ publisher = "Some Publisher",
+ language = "english",
+ title = "Some Title",
+ series = "Some series",
+ booktitle = "Commented Out",
+ number = "3",
+ edition = "Second",
+ year = "1933",
+ pages = "44--59"
+}
+
+@booklet{test-booklet,
+ author = "de Last, Jr., First Middle",
+ language = "english",
+ title = "Just a booklet",
+ year = 2006,
+ month = jan,
+ address = "Moscow",
+ howpublished = "Published by Foo"
+}
+
diff --git a/tests/examplefiles/test.cr b/tests/examplefiles/test.cr
new file mode 100644
index 00000000..028ff6f3
--- /dev/null
+++ b/tests/examplefiles/test.cr
@@ -0,0 +1,2871 @@
+# Examples taken from http://crystal-lang.org/docs/
+# Copyright 2012-2016 Manas Technology Solutions.
+
+
+require "http/server"
+
+server = HTTP::Server.new(8080) do |context|
+ context.response.content_type = "text/plain"
+ context.response.print "Hello world! The time is #{Time.now}"
+end
+
+puts "Listening on http://0.0.0.0:8080"
+server.listen
+
+
+module HTTP
+ class RequestHandler
+ end
+end
+
+alias NumericValue = Float32 | Float64 | Int32 | Int64
+
+enum Time::DayOfWeek
+end
+
+
+$global_greeting = "Hello world"
+
+class Greeting
+ @@default_greeting = "Hello world"
+
+ def initialize(@custom_greeting = nil)
+ end
+
+ def print_greeting
+ greeting = @custom_greeting || @@default_greeting
+ puts greeting
+ end
+end
+
+
+LUCKY_NUMBERS = [3, 7, 11]
+DOCUMENTATION_URL = "http://crystal-lang.org/docs"
+
+
+module Scorecard
+ class Parser
+ def parse(score_text)
+ begin
+ score_text.scan(SCORE_PATTERN) do |match|
+ handle_match(match)
+ end
+ rescue err : ParseError
+ # handle error ...
+ end
+ end
+ end
+end
+
+
+module Money
+ CURRENCIES = {
+ "EUR" => 1.0,
+ "ARS" => 10.55,
+ "USD" => 1.12,
+ "JPY" => 134.15,
+ }
+
+ class Amount
+ getter :currency, :value
+
+ def initialize(@currency, @value)
+ end
+ end
+
+ class CurrencyConversion
+ def initialize(@amount, @target_currency)
+ end
+
+ def amount
+ # implement conversion ...
+ end
+ end
+end
+
+
+i = 0
+while i < 10
+ proc = ->(x : Int32) do
+ spawn do
+ puts(x)
+ end
+ end
+ proc.call(i)
+ i += 1
+end
+
+Fiber.yield
+
+
+# A buffered channel of capacity 2
+channel = Channel(Int32).new(2)
+
+spawn do
+ channel.send(1)
+ channel.send(2)
+ channel.send(3)
+end
+
+3.times do |i|
+ puts channel.receive
+end
+
+
+class MyDictionary(K, V)
+end
+
+
+MyBox.new(1) #:: MyBox(Int32)
+MyBox.new("hello") #:: MyBox(String)
+
+
+module Moo(T)
+ def t
+ T
+ end
+end
+
+class Foo(U)
+ include Moo(U)
+
+ def initialize(@value : U)
+ end
+end
+
+foo = Foo.new(1)
+foo.t # Int32
+
+
+class Parent(T)
+end
+
+class Int32Child < Parent(Int32)
+end
+
+class GenericChild(T) < Parent(T)
+end
+
+
+class Person
+end
+
+
+a = 1
+ptr = pointerof(a)
+ptr[100_000] = 2 # undefined behaviour, probably a segmentation fault
+
+
+alias Int32OrString = Int32 | String
+
+
+alias Int32OrNil = Int32?
+
+
+alias Int32OrNil_ = Int32 | ::Nil
+
+
+alias Int32Ptr = Int32*
+
+
+alias Int32Ptr_ = Pointer(Int32)
+
+
+alias Int32_8 = Int32[8]
+
+
+alias Int32_8_ = StaticArray(Int32, 8)
+
+
+alias Int32StringTuple = {Int32, String}
+
+
+alias Int32StringTuple_ = Tuple(Int32, String)
+
+
+alias Int32ToString = Int32 -> String
+
+
+alias Int32ToString_ = Proc(Int32, String)
+
+
+alias ProcThatReturnsInt32 = -> Int32
+
+
+alias Int32AndCharToString = Int32, Char -> String
+
+
+alias ComplexProc = (Int32 -> Int32) -> String
+
+
+def foo(x : Int32)
+ "instance"
+end
+
+def foo(x : Int32.class)
+ "class"
+end
+
+foo 1 # "instance"
+foo Int32 # "class"
+
+
+class Parent
+end
+
+class Child1 < Parent
+end
+
+class Child2 < Parent
+end
+
+ary = [] of Parent.class
+ary << Child1
+ary << Child2
+
+
+# Same as not specifying a restriction, not very useful
+def foo(x : _)
+end
+
+# A bit more useful: any two arguments Proc that returns an Int32:
+def foo(x : _, _ -> Int32)
+end
+
+
+#alias SameAsInt32 = typeof(2)
+#alias Int32OrString_ = typeof(1, "a")
+
+
+class Person
+ def initialize(name)
+ @name = name
+ @age = 0
+ end
+
+ def name
+ @name
+ end
+
+ def age
+ @age
+ end
+end
+
+
+john = Person.new "John"
+peter = Person.new "Peter"
+
+john.name #=> "John"
+john.age #=> 0
+
+peter.name #=> "Peter"
+
+
+class Person
+ def self.new(name)
+ instance = Person.allocate
+ instance.initialize(name)
+ instance
+ end
+ end
+
+
+if a.is_a?(String)
+ # here a is a String
+end
+
+if b.is_a?(Number)
+ # here b is a Number
+end
+
+
+a = some_condition ? 1 : "hello"
+# a : Int32 | String
+
+if a.is_a?(Number)
+ # a : Int32
+else
+ # a : String
+end
+
+
+if a.is_a?(String) && b.is_a?(Number)
+ # here a is a String and b is a Number
+end
+
+
+a.+(b)
+
+
+struct Vector2
+ getter x, y
+
+ def initialize(@x, @y)
+ end
+
+ def +(other)
+ Vector2.new(x + other.x, y + other.y)
+ end
+end
+
+v1 = Vector2.new(1, 2)
+v2 = Vector2.new(3, 4)
+v1 + v2 #=> Vector2(@x=4, @y=6)
+
+
+
+
+struct Vector2
+ def -
+ Vector2.new(-x, -y)
+ end
+end
+
+v1 = Vector2.new(1, 2)
+-v1 #=> Vector2(@x=-1, @y=-2)
+
+
+
+
+
+class MyArray
+ def [](index)
+ # ...
+ end
+
+ def [](index1, index2, index3)
+ # ...
+ end
+
+ def []=(index, value)
+ # ...
+ end
+end
+
+array = MyArray.new
+
+array[1] # invokes the first method
+array[1, 2, 3] # invokes the second method
+array[1] = 2 # invokes the third method
+
+array.[](1) # invokes the first method
+array.[](1, 2, 3) # invokes the second method
+array.[]=(1, 2) # invokes the third method
+
+
+raise "OH NO!"
+raise Exception.new("Some error")
+
+
+class MyException < Exception
+end
+
+
+begin
+ raise MyException.new("OH NO!")
+rescue ex : MyException
+ puts "Rescued MyException: #{ex.message}"
+end
+
+
+begin
+ # ...
+rescue ex : MyException | MyOtherException
+ # only MyException or MyOtherException
+rescue
+ # any other kind of exception
+ensure
+ puts "Cleanup..."
+end
+
+
+def some_method
+ something_dangerous
+rescue
+ # execute if an exception is raised
+end
+
+
+array = [1, 2, 3]
+array[4] # raises because of IndexError
+array[4]? # returns nil because of index out of bounds
+
+
+def some_proc(&block : Int32 -> Int32)
+ block
+end
+
+x = 0
+proc = ->(i : Int32) { x += i }
+proc = some_proc(&proc)
+proc.call(1) #=> 1
+proc.call(10) #=> 11
+x #=> 11
+
+
+def add(x, y)
+ x + y
+end
+
+adder = ->add(Int32, Int32)
+adder.call(1, 2) #=> 3
+
+
+module Curses
+ class Window
+ end
+end
+
+Curses::Window.new
+
+
+module ItemsSize
+ def size
+ items.size
+ end
+end
+
+class Items
+ include ItemsSize
+
+ def items
+ [1, 2, 3]
+ end
+end
+
+items = Items.new
+items.size #=> 3
+
+
+module Base64
+ extend self
+
+ def encode64(string)
+ # ...
+ end
+
+ def decode64(string)
+ # ...
+ end
+end
+
+Base64.encode64 "hello" #=> "aGVsbG8="
+
+
+if some_condition
+ a = 1
+else
+ a = "hello"
+end
+
+a_as_int = a as Int32
+a_as_int.abs # works, compiler knows that a_as_int is Int32
+
+
+ptr = Pointer(Int32).malloc(1)
+ptr as Int8* #:: Pointer(Int8)
+
+
+array = [1, 2, 3]
+
+# object_id returns the address of an object in memory,
+# so we create a pointer with that address
+ptr = Pointer(Void).new(array.object_id)
+
+# Now we cast that pointer to the same type, and
+# we should get the same value
+array2 = ptr as Array(Int32)
+array2.same?(array) #=> true
+
+
+a = 1
+b = a as Int32 | Float64
+b #:: Int32 | Float64
+
+
+ary = [1, 2, 3]
+
+# We want to create an array 1, 2, 3 of Int32 | Float64
+ary2 = ary.map { |x| x as Int32 | Float64 }
+
+ary2 #:: Array(Int32 | Float64)
+ary2 << 1.5 # OK
+
+
+class Person
+ def initialize(@name)
+ end
+
+ def name
+ @name
+ end
+end
+
+a = [] of Person
+x = a.map { |f| f.name } # Error: can't infer block return type
+
+
+a = [] of Person
+x = a.map { |f| f.name as String } # OK
+
+
+Person.new "John"
+
+a = [] of Person
+x = a.map { |f| f.name } # OK
+
+
+loop do
+ do_something
+ break if some_condition
+end
+
+
+class Point
+ def initialize(@x, @y)
+ end
+end
+
+Point.new 1, 2
+
+# 2 x Int32 = 2 x 4 = 8
+instance_sizeof(Point) #=> 12
+
+
+a = 1
+while a < 5
+ a += 1
+ if a == 3
+ next
+ end
+ puts a
+end
+# The above prints the numbers 2, 4 and 5
+
+
+lib C
+ # In C: double cos(double x)
+ fun cos(value : Float64) : Float64
+
+ fun getch : Int32
+
+ fun srand(seed : UInt32)
+
+ fun exit(status : Int32) : NoReturn
+
+ fun printf(format : UInt8*, ...) : Int32
+end
+
+C.cos(1.5) #=> 0.0707372
+C.srand(1_u32)
+
+a = 1
+b = 2
+C.printf "%d + %d = %d\n", a, b, a + b
+
+
+lib LibSDL
+ fun init = SDL_Init(flags : UInt32) : Int32
+end
+
+lib LLVMIntrinsics
+ fun ceil_f32 = "llvm.ceil.f32"(value : Float32) : Float32
+end
+
+lib MyLib
+ fun my_fun(some_size : LibC::SizeT)
+end
+
+@[Link("pcre")]
+lib LibPCRE
+end
+
+
+lib C
+ ifdef x86_64
+ alias SizeT = UInt64
+ else
+ alias SizeT = UInt32
+ end
+
+ fun memcmp(p1 : Void*, p2 : Void*, size : C::SizeT) : Int32
+end
+
+
+lib X
+ enum SomeEnum
+ Ten = 10
+ Twenty = 10 * 2
+ ThirtyTwo = 1 << 5
+ end
+end
+
+
+lib X
+ enum SomeEnum
+ A = 1_u32
+ end
+end
+
+
+X::SomeEnum::Zero #=> 0_i8
+X::SomeEnum::Two #=> 2_i8
+
+
+lib X
+ fun callback(f : Int32 -> Int32)
+end
+
+
+f = ->(x : Int32) { x + 1 }
+X.callback(f)
+
+
+X.callback ->(x) { x + 1 }
+
+
+X.callback nil
+
+
+lib LibFoo
+ fun store_callback(callback : ->)
+ fun execute_callback
+end
+
+LibFoo.store_callback ->{ raise "OH NO!" }
+LibFoo.execute_callback
+
+
+lib LibFoo
+ fun store_callback(callback : ->)
+
+ @[Raises]
+ fun execute_callback
+end
+
+
+@[Link("pcre")]
+lib PCRE
+ INFO_CAPTURECOUNT = 2
+end
+
+PCRE::INFO_CAPTURECOUNT #=> 2
+
+
+lib U
+ # In C:
+ #
+ # union IntOrFloat {
+ # int some_int;
+ # double some_float;
+ # };
+ union IntOrFloat
+ some_int : Int32
+ some_float : Float64
+ end
+end
+
+
+value = U::IntOrFloat.new
+
+
+value = uninitialized U::IntOrFlaot
+value.some_int #=> some garbage value
+
+
+value = U::IntOrFloat.new
+value.some_int = 1
+value.some_int #=> 1
+value.some_float #=> 4.94066e-324
+
+
+def change_it(value)
+ value.some_int = 1
+end
+
+value = U::IntOrFloat.new
+change_it value
+value.some_int #=> 0
+
+
+lib C
+ # In C:
+ #
+ # struct TimeZone {
+ # int minutes_west;
+ # int dst_time;
+ # };
+ struct TimeZone
+ minutes_west : Int32
+ dst_time : Int32
+ end
+end
+
+
+lib C
+ # This is a forward declaration
+ struct Node
+ end
+
+ struct Node
+ node : Node*
+ end
+end
+
+
+tz = C::TimeZone.new
+
+
+tz = uninitialized C::TimeZone
+tz.minutes_west #=> some garbage value
+
+
+tz = C::TimeZone.new
+tz.minutes_west = 1
+tz.minutes_west #=> 1
+
+
+tz = C::TimeZone.new minutes_west: 1, dst_time: 2
+tz.minutes_west #=> 1
+tz.dst_time #=> 2
+
+
+def change_it(tz)
+ tz.minutes_west = 1
+end
+
+tz = C::TimeZone.new
+change_it tz
+tz.minutes_west #=> 0
+
+
+lib C
+ $errno : Int32
+end
+
+
+C.errno #=> some value
+C.errno = 0
+C.errno #=> 0
+
+
+lib C
+ @[ThreadLocal]
+ $errno : Int32
+end
+
+
+lib C
+ fun waitpid(pid : Int32, status_ptr : Int32*, options : Int32) : Int32
+end
+
+
+status_ptr = uninitialized Int32
+
+C.waitpid(pid, pointerof(status_ptr), options)
+
+
+C.waitpid(pid, out status_ptr, options)
+
+
+lib X
+ type CInt = Int32
+end
+
+
+ifdef x86_64
+ # some specific code for 64 bits platforms
+else
+ # some specific code for non-64 bits platforms
+end
+
+
+ifdef linux && x86_64
+ # some specific code for linux 64 bits
+end
+
+
+lib C
+ ifdef linux
+ struct SomeStruct
+ some_field : Int32
+ end
+ else
+ struct SomeStruct
+ some_field : Int64
+ end
+ end
+end
+
+
+# Assigns to a local variable
+local = 1
+
+# Assigns to a global variable
+$global = 4
+
+class Testing
+ # Assigns to an instance variable
+ @instance = 2
+
+ # Assigns to a class variable
+ @@class = 3
+end
+
+
+local += 1 # same as: local = local + 1
+
+# The above is valid with these operators:
+# +, -, *, /, %, |, &, ^, **, <<, >>
+
+local ||= 1 # same as: local || (local = 1)
+local &&= 1 # same as: local && (local = 1)
+
+
+# A setter
+person.name=("John")
+
+# The above can be written as:
+person.name = "John"
+
+# An indexed assignment
+objects.[]=(2, 3)
+
+# The above can be written as:
+objects[2] = 3
+
+# Not assignment-related, but also syntax sugar:
+objects.[](2, 3)
+
+# The above can be written as:
+objects[2, 3]
+
+
+person.age += 1 # same as: person.age = person.age + 1
+
+person.name ||= "John" # same as: person.name || (person.name = "John")
+person.name &&= "John" # same as: person.name && (person.name = "John")
+
+objects[1] += 2 # same as: objects[1] = objects[1] + 2
+
+objects[1] ||= 2 # same as: objects[1]? || (objects[1] = 2)
+objects[1] &&= 2 # same as: objects[1]? && (objects[1] = 2)
+
+
+alias PInt32 = Pointer(Int32)
+
+ptr = PInt32.malloc(1) # : Pointer(Int32)
+
+
+alias RecArray = Array(Int32) | Array(RecArray)
+
+ary = [] of RecArray
+ary.push [1, 2, 3]
+ary.push ary
+ary #=> [[1, 2, 3], [...]]
+
+
+module Json
+ alias Type = Nil |
+ Bool |
+ Int64 |
+ Float64 |
+ String |
+ Array(Type) |
+ Hash(String, Type)
+end
+
+
+a = 1
+if a > 0
+ a = 10
+end
+a #=> 10
+
+b = 1
+if b > 2
+ b = 10
+else
+ b = 20
+end
+b #=> 20
+
+
+if some_condition
+ do_something
+elsif some_other_condition
+ do_something_else
+else
+ do_that
+end
+
+
+a = 1
+if some_condition
+ a = "hello"
+else
+ a = true
+end
+# a : String | Bool
+
+b = 1
+if some_condition
+ b = "hello"
+end
+# b : Int32 | String
+
+if some_condition
+ c = 1
+else
+ c = "hello"
+end
+# c : Int32 | String
+
+if some_condition
+ d = 1
+end
+# d : Int32 | Nil
+
+
+a = 1
+if some_condition
+ a = "hello"
+ # a : String
+ a.size
+end
+# a : String | Int32
+
+
+if some_condition
+ e = 1
+else
+ e = "hello"
+ # e : String
+ return
+end
+# e : Int32
+
+
+enum Color : UInt8
+ Red # 0
+ Green # 1
+ Blue = 5 # overwritten to 5
+ Yellow # 6 (5 + 1)
+
+ def red?
+ self == Color::Red
+ end
+end
+
+Color::Red.value #:: UInt8
+
+
+@[Flags]
+enum IOMode
+ Read # 1
+ Write # 2
+ Async # 4
+end
+
+
+IOMode::None.value #=> 0
+IOMode::All.value #=> 7
+
+
+puts(Color::Red) # prints "Red"
+puts(IOMode::Write | IOMode::Async) # prints "Write, Async"
+
+
+puts Color.new(1) #=> prints "Green"
+
+
+puts Color.new(10) #=> prints "10"
+
+
+Color::Red.red? #=> true
+Color::Blue.red? #=> false
+
+
+def paint(color : Color)
+ case color
+ when Color::Red
+ # ...
+ else
+ # Unusual, but still can happen
+ raise "unknown color: #{color}"
+ end
+end
+
+paint Color::Red
+
+
+def paint(color : Symbol)
+ case color
+ when :red
+ # ...
+ else
+ raise "unknown color: #{color}"
+ end
+end
+
+paint :red
+
+
+name = "Crystal"
+age = 1
+
+
+flower = "Tulip"
+# At this point 'flower' is a String
+
+flower = 1
+# At this point 'flower' is an Int32
+
+
+class Foo
+ def finalize
+ # Invoked when Foo is garbage-collected
+ puts "Bye bye from #{self}!"
+ end
+end
+
+# Prints "Bye bye ...!" for ever
+loop do
+ Foo.new
+end
+
+
+# Defines a method in the program
+def add(x, y)
+ x + y
+end
+
+# Invokes the add method in the program
+add(1, 2) #=> 3
+
+
+def even?(num)
+ if num % 2 == 0
+ return true
+ end
+
+ return false
+end
+
+
+def add(x, y)
+ x + y
+end
+
+class Foo
+ def bar
+ # invokes the program's add method
+ add(1, 2)
+
+ # invokes Foo's baz method
+ baz(1, 2)
+ end
+
+ def baz(x, y)
+ x * y
+ end
+end
+
+
+def baz(x, y)
+ x + y
+end
+
+class Foo
+ def bar
+ baz(4, 2) #=> 2
+ ::baz(4, 2) #=> 6
+ end
+
+ def baz(x, y)
+ x - y
+ end
+end
+
+
+x = 1
+
+def add(y)
+ x + y # error: undefined local variable or method 'x'
+end
+
+add(2)
+
+
+add 1, 2 # same as add(1, 2)
+
+
+class Counter
+ @@instances = 0
+
+ def initialize
+ @@instances += 1
+ end
+
+ def self.instances
+ @@instances
+ end
+end
+
+Counter.instances #=> 0
+Counter.new
+Counter.new
+Counter.new
+Counter.instances #=> 3
+
+
+class Counter
+ def self.increment
+ @@instances += 1
+ end
+end
+
+Counter.increment # Error: undefined method '+' for Nil
+
+
+class Parent
+ @@counter = 0
+end
+
+class Child < Parent
+ def self.counter
+ @@counter
+ end
+end
+
+Child.counter #=> nil
+
+
+unless some_condition
+ then_expression
+else
+ else_expression
+end
+
+# Can also be written as a suffix
+close_door unless door_closed?
+
+
+a = 1
+b = typeof(a) #=> Int32
+
+
+typeof(1, "a", 'a') #=> (Int32 | String | Char)
+
+
+hash = {} of Int32 => String
+another_hash = typeof(hash).new #:: Hash(Int32, String)
+
+
+class Array
+ def self.elem_type(typ)
+ if typ.is_a?(Array)
+ elem_type(typ.first)
+ else
+ typ
+ end
+ end
+end
+
+nest = [1, ["b", [:c, ['d']]]]
+flat = Array(typeof(Array.elem_type(nest))).new
+typeof(nest) #=> Array(Int32 | Array(String | Array(Symbol | Array(Char))))
+typeof(flat) #=> Array(String | Int32 | Symbol | Char)
+
+
+a = 2 if some_condition
+
+
+x = 0
+proc = ->{ x += 1; x }
+proc.call #=> 1
+proc.call #=> 2
+x #=> 2
+
+
+def counter
+ x = 0
+ ->{ x += 1; x }
+end
+
+proc = counter
+proc.call #=> 1
+proc.call #=> 2
+
+
+def foo
+ yield
+end
+
+x = 1
+foo do
+ x = "hello"
+end
+x # : Int32 | String
+
+
+x = 1
+foo do
+ x = "hello"
+end
+x # : Int32 | String
+
+x = 'a'
+x # : Char
+
+
+def capture(&block)
+ block
+end
+
+x = 1
+capture { x = "hello" }
+
+x = 'a'
+x # : Int32 | String | Char
+
+
+def capture(&block)
+ block
+end
+
+x = 1
+->{ x = "hello" }
+
+x = 'a'
+x # : Int32 | String | Char
+
+
+abstract class Animal
+ # Makes this animal talk
+ abstract def talk
+end
+
+class Dog < Animal
+ def talk
+ "Woof!"
+ end
+end
+
+class Cat < Animal
+ def talk
+ "Miau"
+ end
+end
+
+class Person
+ getter pet
+
+ def initialize(@name, @pet)
+ end
+end
+
+john = Person.new "John", Dog.new
+peter = Person.new "Peter", Cat.new
+
+
+john.pet.talk #=> "Woof!"
+
+
+a = 1 > 2 ? 3 : 4
+
+# The above is the same as:
+a = if 1 > 2
+ 3
+ else
+ 4
+ end
+
+
+def some_method : String
+ "hello"
+end
+
+
+PI = 3.14
+
+module Earth
+ RADIUS = 6_371_000
+end
+
+PI #=> 3.14
+Earth::RADIUS #=> 6_371_000
+
+
+TEN = begin
+ a = 0
+ while a < 10
+ a += 1
+ end
+ a
+end
+
+TEN #=> 10
+
+
+class Person
+ getter name
+
+ def initialize(@name)
+ @age = 0
+ end
+end
+
+john = Person.new "John"
+john.name #=> "John"
+john.name.size #=> 4
+
+
+one = Person.new 1
+one.name #=> 1
+one.name + 2 #=> 3
+
+
+john = Person.new "John"
+one = Person.new 1
+
+
+john = Person.new "John"
+one = Person.new 1
+
+# Error: undefined method 'size' for Int32
+john.name.size
+
+# Error: no overload matches 'String#+' with types Int32
+john.name + 3
+
+
+john = Person.new "John"
+john.name.size
+one = Person.new 1
+
+
+class Person
+ getter name
+
+ def initialize(@name)
+ @age = 0
+ end
+
+ def address
+ @address
+ end
+
+ def address=(@address)
+ end
+end
+
+john = Person.new "John"
+john.address = "Argentina"
+
+
+# Error: undefined method 'size' for Nil
+john.address.size
+
+
+class Person
+ @age = 0
+
+ def initialize(@name)
+ end
+end
+
+
+class Person
+ @age : Int32
+
+ def initialize(@name)
+ @age = 0
+ end
+end
+
+
+a = if 2 > 1
+ 3
+ else
+ 4
+ end
+a #=> 3
+
+
+if 1 > 2
+else
+ 3
+end
+
+
+def twice(&block)
+ yield
+ yield
+end
+
+
+twice() do
+ puts "Hello!"
+end
+
+twice do
+ puts "Hello!"
+end
+
+twice { puts "Hello!" }
+
+
+def twice
+ yield 1
+ yield 2
+end
+
+twice do |i|
+ puts "Got #{i}"
+end
+
+
+twice { |i| puts "Got #{i}" }
+
+
+def many
+ yield 1, 2, 3
+end
+
+many do |x, y, z|
+ puts x + y + z
+end
+
+# Output: 6
+
+
+def many
+ yield 1, 2, 3
+end
+
+many do |x, y|
+ puts x + y
+end
+
+# Output: 3
+
+
+def twice
+ yield
+ yield
+end
+
+twice do |i|
+ puts i.inspect
+end
+
+
+def some
+ yield 1, 'a'
+ yield true, "hello"
+ yield 2
+end
+
+some do |first, second|
+ # first is Int32 | Bool
+ # second is Char | String | Nil
+end
+
+
+method do |argument|
+ argument.some_method
+end
+
+
+method(&.some_method)
+
+
+method &.some_method(arg1, arg2)
+
+
+method &.+(2)
+method &.[index]
+
+
+def twice
+ v1 = yield 1
+ puts v1
+
+ v2 = yield 2
+ puts v2
+end
+
+twice do |i|
+ i + 1
+end
+
+
+ary = [1, 2, 3]
+ary.map { |x| x + 1 } #=> [2, 3, 4]
+ary.select { |x| x % 2 == 1 } #=> [1, 3]
+
+
+def transform(value)
+ yield value
+end
+
+transform(1) { |x| x + 1 } #=> 2
+
+
+def thrice
+ puts "Before 1"
+ yield 1
+ puts "Before 2"
+ yield 2
+ puts "Before 3"
+ yield 3
+ puts "After 3"
+end
+
+thrice do |i|
+ if i == 2
+ break
+ end
+end
+
+
+def twice
+ yield 1
+ yield 2
+end
+
+twice { |i| i + 1 } #=> 3
+twice { |i| break "hello" } #=> "hello"
+
+
+value = twice do |i|
+ if i == 1
+ break "hello"
+ end
+ i + 1
+end
+value #:: Int32 | String
+
+
+values = twice { break 1, 2 }
+values #=> {1, 2}
+
+
+value = twice { break }
+value #=> nil
+
+
+def twice
+ yield 1
+ yield 2
+end
+
+twice do |i|
+ if i == 1
+ puts "Skipping 1"
+ next
+ end
+
+ puts "Got #{i}"
+end
+
+
+
+def twice
+ v1 = yield 1
+ puts v1
+
+ v2 = yield 2
+ puts v2
+end
+
+twice do |i|
+ if i == 1
+ next 10
+ end
+
+ i + 1
+end
+
+# Output
+# 10
+# 3
+
+
+class Foo
+ def one
+ 1
+ end
+
+ def yield_with_self
+ with self yield
+ end
+
+ def yield_normally
+ yield
+ end
+end
+
+def one
+ "one"
+end
+
+Foo.new.yield_with_self { one } # => 1
+Foo.new.yield_normally { one } # => "one"
+
+
+def twice
+ yield 1
+ yield 2
+end
+
+twice do |i|
+ puts "Got: #{i}"
+end
+
+
+i = 1
+puts "Got: #{i}"
+i = 2
+puts "Got: #{i}"
+
+
+3.times do |i|
+ puts i
+end
+
+
+struct Int
+ def times
+ i = 0
+ while i < self
+ yield i
+ i += 1
+ end
+ end
+end
+
+
+i = 0
+while i < 3
+ puts i
+ i += 1
+end
+
+
+class Person
+ def initialize(@name)
+ end
+
+ def greet
+ puts "Hi, I'm #{@name}"
+ end
+end
+
+class Employee < Person
+end
+
+employee = Employee.new "John"
+employee.greet # "Hi, I'm John"
+
+
+class Person
+ def initialize(@name)
+ end
+end
+
+class Employee < Person
+ def initialize(@name, @company_name)
+ end
+end
+
+Employee.new "John", "Acme" # OK
+Employee.new "Peter" # Error: wrong number of arguments
+ # for 'Employee:Class#new' (1 for 2)
+
+
+class Person
+ def greet(msg)
+ puts "Hi, #{msg}"
+ end
+end
+
+class Employee < Person
+ def greet(msg)
+ puts "Hello, #{msg}"
+ end
+end
+
+p = Person.new
+p.greet "everyone" # "Hi, everyone"
+
+e = Employee.new
+e.greet "everyone" # "Hello, everyone"
+
+
+class Person
+ def greet(msg)
+ puts "Hi, #{msg}"
+ end
+end
+
+class Employee < Person
+ def greet(msg : Int32)
+ puts "Hi, this is a number: #{msg}"
+ end
+end
+
+e = Employee.new
+e.greet "everyone" # "Hi, everyone"
+
+e.greet 1 # "Hi, this is a number: 1"
+
+
+class Person
+ def greet(msg)
+ puts "Hello, "#{msg}"
+ end
+end
+
+class Employee < Person
+ def greet(msg)
+ super # Same as: super(msg)
+ super("another message")
+ end
+end
+
+
+def int_to_int(&block : Int32 -> Int32)
+ block
+end
+
+proc = int_to_int { |x| x + 1 }
+proc.call(1) #=> 2
+
+
+class Model
+ def on_save(&block)
+ @on_save_callback = block
+ end
+
+ def save
+ if callback = @on_save_callback
+ callback.call
+ end
+ end
+end
+
+model = Model.new
+model.on_save { puts "Saved!" }
+model.save # prints "Saved!"
+
+
+def some_proc(&block : Int32 ->)
+ block
+end
+
+proc = some_proc { |x| x + 1 }
+proc.call(1) # void
+
+
+def some_proc(&block : Int32 -> _)
+ block
+end
+
+proc = some_proc { |x| x + 1 }
+proc.call(1) # 2
+
+proc = some_proc { |x| x.to_s }
+proc.call(1) # "1"
+
+
+macro update_x
+ x = 1
+end
+
+x = 0
+update_x
+x #=> 1
+
+
+macro dont_update_x
+ %x = 1
+ puts %x
+end
+
+x = 0
+dont_update_x # outputs 1
+x #=> 0
+
+
+macro fresh_vars_sample(*names)
+ # First declare vars
+ {% for name, index in names %}
+ print "Declaring: ", "%name{index}", '\n'
+ %name{index} = {{index}}
+ {% end %}
+
+ # Then print them
+ {% for name, index in names %}
+ print "%name{index}: ", %name{index}, '\n'
+ {% end %}
+end
+
+fresh_vars_sample a, b, c
+
+# Sample output:
+# Declaring: __temp_255
+# Declaring: __temp_256
+# Declaring: __temp_257
+# __temp_255: 0
+# __temp_256: 1
+# __temp_257: 2
+
+
+class Object
+ macro def instance_vars_names : Array(String)
+ {{ @type.instance_vars.map &.name.stringify }}
+ end
+end
+
+class Person
+ def initialize(@name, @age)
+ end
+end
+
+person = Person.new "John", 30
+person.instance_vars_names #=> ["name", "age"]
+
+
+class Object
+ macro def has_instance_var?(name) : Bool
+ # We cannot access name inside the macro expansion here,
+ # instead we need to use the macro language to construct an array
+ # and do the inclusion check at runtime.
+ {{ @type.instance_vars.map &.name.stringify }}.includes? name
+ end
+end
+
+person = Person.new "John", 30
+person.has_instance_var?("name") #=> true
+person.has_instance_var?("birthday") #=> false
+
+
+class Parent
+ macro inherited
+ def {{@type.name.downcase.id}}
+ 1
+ end
+ end
+end
+
+class Child < Parent
+end
+
+Child.new.child #=> 1
+
+
+macro method_missing(name, args, block)
+ print "Got ", {{name.id.stringify}}, " with ", {{args.size}}, " arguments", '\n'
+end
+
+foo # Prints: Got foo with 0 arguments
+bar 'a', 'b' # Prints: Got bar with 2 arguments
+
+
+sizeof(Int32) #=> 4
+sizeof(Int64) #=> 8
+
+
+# On a 64 bits machine
+sizeof(Pointer(Int32)) #=> 8
+sizeof(String) #=> 8
+
+
+a = 1
+sizeof(typeof(a)) #=> 4
+
+
+class Foo
+ macro emphasize(value)
+ "***#{ {{value}} }***"
+ end
+
+ def yield_with_self
+ with self yield
+ end
+end
+
+Foo.new.yield_with_self { emphasize(10) } #=> "***10***"
+
+
+# This generates:
+#
+# def :foo
+# 1
+# end
+define_method :foo, 1
+
+
+macro define_method(name, content)
+ def {{name.id}}
+ {{content}}
+ end
+end
+
+# This correctly generates:
+#
+# def foo
+# 1
+# end
+define_method :foo, 1
+
+
+macro define_method(name, content)
+ def {{name}}
+ {% if content == 1 %}
+ "one"
+ {% else %}
+ {{content}}
+ {% end %}
+ end
+end
+
+define_method foo, 1
+define_method bar, 2
+
+foo #=> one
+bar #=> 2
+
+
+{% if env("TEST") %}
+ puts "We are in test mode"
+{% end %}
+
+
+macro define_dummy_methods(names)
+ {% for name, index in names %}
+ def {{name.id}}
+ {{index}}
+ end
+ {% end %}
+end
+
+define_dummy_methods [foo, bar, baz]
+
+foo #=> 0
+bar #=> 1
+baz #=> 2
+
+
+macro define_dummy_methods(hash)
+ {% for key, value in hash %}
+ def {{key.id}}
+ {{value}}
+ end
+ {% end %}
+end
+define_dummy_methods({foo: 10, bar: 20})
+foo #=> 10
+bar #=> 20
+
+
+{% for name, index in ["foo", "bar", "baz"] %}
+ def {{name.id}}
+ {{index}}
+ end
+{% end %}
+
+foo #=> 0
+bar #=> 1
+baz #=> 2
+
+
+macro define_dummy_methods(*names)
+ {% for name, index in names %}
+ def {{name.id}}
+ {{index}}
+ end
+ {% end %}
+end
+
+define_dummy_methods foo, bar, baz
+
+foo #=> 0
+bar #=> 1
+baz #=> 2
+
+
+macro println(*values)
+ print {{*values}}, '\n'
+end
+
+println 1, 2, 3 # outputs 123\n
+
+
+VALUES = [1, 2, 3]
+
+{% for value in VALUES %}
+ puts {{value}}
+{% end %}
+
+
+until some_condition
+ do_this
+end
+
+# The above is the same as:
+while !some_condition
+ do_this
+end
+
+
+a = some_condition ? nil : 3
+# a is Int32 or Nil
+
+if a
+ # Since the only way to get here is if a is truthy,
+ # a can't be nil. So here a is Int32.
+ a.abs
+end
+
+
+if a = some_expression
+ # here a is not nil
+end
+
+
+if a && b
+ # here both a and b are guaranteed not to be Nil
+end
+
+
+if @a
+ # here @a can be nil
+end
+
+
+# First option: assign it to a variable
+if a = @a
+ # here a can't be nil
+end
+
+# Second option: use `Object#try` found in the standard library
+@a.try do |a|
+ # here a can't be nil
+end
+
+
+if method # first call to a method that can return Int32 or Nil
+ # here we know that the first call did not return Nil
+ method # second call can still return Int32 or Nil
+end
+
+
+class Person
+ def become_older(by = 1)
+ @age += by
+ end
+end
+
+john = Person.new "John"
+john.age #=> 0
+
+john.become_older
+john.age #=> 1
+
+john.become_older 2
+john.age #=> 3
+
+
+john.become_older by: 5
+
+
+def some_method(x, y = 1, z = 2, w = 3)
+ # do something...
+end
+
+some_method 10 # x = 10, y = 1, z = 2, w = 3
+some_method 10, z: 10 # x = 10, y = 1, z = 10, w = 3
+some_method 10, w: 1, y: 2, z: 3 # x = 10, y = 2, z = 3, w = 1
+
+
+case exp
+when value1, value2
+ do_something
+when value3
+ do_something_else
+else
+ do_another_thing
+end
+
+
+case var
+when String
+ # var : String
+ do_something
+when Int32
+ # var : Int32
+ do_something_else
+else
+ # here var is neither a String nor an Int32
+ do_another_thing
+end
+
+
+case num
+when .even?
+ do_something
+when .odd?
+ do_something_else
+end
+
+
+case
+when cond1, cond2
+ do_something
+when cond3
+ do_something_else
+end
+
+
+a = 1
+a.responds_to?(:abs) #=> true
+a.responds_to?(:size) #=> false
+
+
+foo_or_bar = /foo|bar/
+heeello = /h(e+)llo/
+integer = /\d+/
+
+
+r = /foo/imx
+
+
+slash = /\//
+
+
+r = %r(regex with slash: /)
+
+
+"hello world"
+
+
+"\"" # double quote
+"\\" # backslash
+"\e" # escape
+"\f" # form feed
+"\n" # newline
+"\r" # carriage return
+"\t" # tab
+"\v" # vertical tab
+
+
+"\101" # == "A"
+"\123" # == "S"
+"\12" # == "\n"
+"\1" # string with one character with code point 1
+
+
+"\u0041" # == "A"
+
+
+"\u{41}" # == "A"
+"\u{1F52E}" # == "🔮"
+
+
+"hello
+ world" # same as "hello\n world"
+
+
+"hello " \
+"world, " \
+"no newlines" # same as "hello world, no newlines"
+
+
+"hello \
+ world, \
+ no newlines" # same as "hello world, no newlines"
+
+
+# Supports double quotes and nested parenthesis
+%(hello ("world")) # same as "hello (\"world\")"
+
+# Supports double quotes and nested brackets
+%[hello ["world"]] # same as "hello [\"world\"]"
+
+# Supports double quotes and nested curlies
+%{hello {"world"}} # same as "hello {\"world\"}"
+
+# Supports double quotes and nested angles
+%<hello <"world">> # same as "hello <\"world\">"
+
+
+<<-XML
+<parent>
+ <child />
+</parent>
+XML
+
+
+# Same as "Hello\n world"
+<<-STRING
+ Hello
+ world
+ STRING
+
+# Same as " Hello\n world"
+<<-STRING
+ Hello
+ world
+ STRING
+
+
+a = 1
+b = 2
+"sum = #{a + b}" # "sum = 3"
+
+
+1.0 # Float64
+1.0_f32 # Float32
+1_f32 # Float32
+
+1e10 # Float64
+1.5e10 # Float64
+1.5e-7 # Float64
+
++1.3 # Float64
+-0.5 # Float64
+
+
+1_000_000.111_111 # better than 1000000.111111
+
+
+'a'
+'z'
+'0'
+'_'
+'あ'
+
+
+'\'' # single quote
+'\\' # backslash
+'\e' # escape
+'\f' # form feed
+'\n' # newline
+'\r' # carriage return
+'\t' # tab
+'\v' # vertical tab
+
+
+'\101' # == 'A'
+'\123' # == 'S'
+'\12' # == '\n'
+'\1' # code point 1
+
+
+'\u0041' # == 'A'
+
+
+'\u{41}' # == 'A'
+'\u{1F52E}' # == '🔮'
+
+
+{1 => 2, 3 => 4} # Hash(Int32, Int32)
+{1 => 2, 'a' => 3} # Hash(Int32 | Char, Int32)
+
+
+{} of Int32 => Int32 # same as Hash(Int32, Int32).new
+
+
+{key1: 'a', key2: 'b'} # Hash(Symbol, Char)
+
+
+{"key1": 'a', "key2": 'b'} # Hash(String, Char)
+
+
+MyType{"foo": "bar"}
+
+
+tmp = MyType.new
+tmp["foo"] = "bar"
+tmp
+
+
+tmp = MyType(typeof("foo"), typeof("bar")).new
+tmp["foo"] = "bar"
+tmp
+
+
+MyType(String, String) {"foo": "bar"}
+
+
+:hello
+:good_bye
+
+# With spaces and symbols
+:"symbol with spaces"
+
+# Ending with question and exclamation marks
+:question?
+:exclamation!
+
+# For the operators
+:+
+:-
+:*
+:/
+:==
+:<
+:<=
+:>
+:>=
+:!
+:!=
+:=~
+:!~
+:&
+:|
+:^
+:~
+:**
+:>>
+:<<
+:%
+:[]
+:[]?
+:[]=
+:<=>
+:===
+
+
+x..y # an inclusive range, in mathematics: [x, y]
+x...y # an exclusive range, in mathematics: [x, y)
+
+
+# A proc without arguments
+->{ 1 } # Proc(Int32)
+
+# A proc with one argument
+->(x : Int32) { x.to_s } # Proc(Int32, String)
+
+# A proc with two arguments:
+->(x : Int32, y : Int32) { x + y } # Proc(Int32, Int32, Int32)
+
+
+Proc(Int32, String).new { |x| x.to_s } # Proc(Int32, String)
+
+
+proc = ->(x : Int32, y : Int32) { x + y }
+proc.call(1, 2) #=> 3
+
+
+def one
+ 1
+end
+
+proc = ->one
+proc.call #=> 1
+
+
+def plus_one(x)
+ x + 1
+end
+
+proc = ->plus_one(Int32)
+proc.call(41) #=> 42
+
+
+str = "hello"
+proc = ->str.count(Char)
+proc.call('e') #=> 1
+proc.call('l') #=> 2
+
+
+tuple = {1, "hello", 'x'} # Tuple(Int32, String, Char)
+tuple[0] #=> 1 (Int32)
+tuple[1] #=> "hello" (String)
+tuple[2] #=> 'x' (Char)
+
+
+[1, 2, 3] # Array(Int32)
+[1, "hello", 'x'] # Array(Int32 | String | Char)
+
+
+[] of Int32 # same as Array(Int32).new
+
+
+%w(one two three) # ["one", "two", "three"]
+
+
+%i(one two three) # [:one, :two, :three]
+
+
+MyType{1, 2, 3}
+
+
+tmp = MyType.new
+tmp << 1
+tmp << 2
+tmp << 3
+tmp
+
+
+tmp = MyType(typeof(1, 2, 3)).new
+tmp << 1
+tmp << 2
+tmp << 3
+tmp
+
+
+MyType(Int32 | String) {1, 2, "foo"}
+
+
+nil
+
+
+1 # Int32
+
+1_i8 # Int8
+1_i16 # Int16
+1_i32 # Int32
+1_i64 # Int64
+
+1_u8 # UInt8
+1_u16 # UInt16
+1_u32 # UInt32
+1_u64 # UInt64
+
++10 # Int32
+-20 # Int32
+
+2147483648 # Int64
+9223372036854775808 # UInt64
+
+
+1_000_000 # better than 1000000
+
+
+0b1101 # == 13
+
+
+0o123 # == 83
+
+
+0xFE012D # == 16646445
+0xfe012d # == 16646445
+
+
+true # A Bool that is true
+false # A Bool that is false
+
+
+a = 1
+
+ptr = pointerof(a)
+ptr.value = 2
+
+a #=> 2
+
+
+class Point
+ def initialize(@x, @y)
+ end
+
+ def x
+ @x
+ end
+
+ def x_ptr
+ pointerof(@x)
+ end
+end
+
+point = Point.new 1, 2
+
+ptr = point.x_ptr
+ptr.value = 10
+
+point.x #=> 10
+
+
+def add(x : Number, y : Number)
+ x + y
+end
+
+# Ok
+add 1, 2 # Ok
+
+# Error: no overload matches 'add' with types Bool, Bool
+add true, false
+
+
+def add(x, y)
+ x + y
+end
+
+add true, false
+
+
+# A class that has a + method but isn't a Number
+class Six
+ def +(other)
+ 6 + other
+ end
+end
+
+# add method without type restrictions
+def add(x, y)
+ x + y
+end
+
+# OK
+add Six.new, 10
+
+# add method with type restrictions
+def restricted_add(x : Number, y : Number)
+ x + y
+end
+
+# Error: no overload matches 'restricted_add' with types Six, Int32
+restricted_add Six.new, 10
+
+
+class Person
+ def ==(other : self)
+ other.name == name
+ end
+
+ def ==(other)
+ false
+ end
+end
+
+john = Person.new "John"
+another_john = Person.new "John"
+peter = Person.new "Peter"
+
+john == another_john #=> true
+john == peter #=> false (names differ)
+john == 1 #=> false (because 1 is not a Person)
+
+
+class Person
+ def self.compare(p1 : self, p2 : self)
+ p1.name == p2.name
+ end
+end
+
+john = Person.new "John"
+peter = Person.new "Peter"
+
+Person.compare(john, peter) # OK
+
+
+def foo(x : Int32)
+end
+
+foo 1 # OK
+foo "hello" # Error
+
+
+def foo(x : Int32.class)
+end
+
+foo Int32 # OK
+foo String # Error
+
+
+def foo(x : Int32.class)
+ puts "Got Int32"
+end
+
+def foo(x : String.class)
+ puts "Got String"
+end
+
+foo Int32 # prints "Got Int32"
+foo String # prints "Got String"
+
+
+def foo(*args : Int32)
+end
+
+def foo(*args : String)
+end
+
+foo 1, 2, 3 # OK, invokes first overload
+foo "a", "b", "c" # OK, invokes second overload
+foo 1, 2, "hello" # Error
+foo() # Error
+
+
+def foo
+ # This is the empty-tuple case
+end
+
+
+def foo(x : T)
+ T
+end
+
+foo(1) #=> Int32
+foo("hello") #=> String
+
+
+def foo(x : Array(T))
+ T
+end
+
+foo([1, 2]) #=> Int32
+foo([1, "a"]) #=> (Int32 | String)
+
+
+def foo(x : T.class)
+ Array(T)
+end
+
+foo(Int32) #=> Array(Int32)
+foo(String) #=> Array(String)
+
+
+class Person
+ # Increases age by one
+ def become_older
+ @age += 1
+ end
+
+ # Increases age by the given number of years
+ def become_older(years : Int32)
+ @age += years
+ end
+
+ # Increases age by the given number of years, as a String
+ def become_older(years : String)
+ @age += years.to_i
+ end
+
+ # Yields the current age of this person and increases
+ # its age by the value returned by the block
+ def become_older
+ @age += yield @age
+ end
+end
+
+person = Person.new "John"
+
+person.become_older
+person.age #=> 1
+
+person.become_older 5
+person.age #=> 6
+
+person.become_older "12"
+person.age #=> 18
+
+person.become_older do |current_age|
+ current_age < 20 ? 10 : 30
+end
+person.age #=> 28
+
+
+a = 1
+a.is_a?(Int32) #=> true
+a.is_a?(String) #=> false
+a.is_a?(Number) #=> true
+a.is_a?(Int32 | String) #=> true
+
+
+# One for each thread
+@[ThreadLocal]
+$values = [] of Int32
+
+
+@[AlwaysInline]
+def foo
+ 1
+end
+
+
+@[NoInline]
+def foo
+ 1
+end
+
+
+lib LibFoo
+ @[CallConvention("X86_StdCall")]
+ fun foo : Int32
+end
+
+
+def sum(*elements)
+ total = 0
+ elements.each do |value|
+ total += value
+ end
+ total
+end
+
+# elements is Tuple(Int32, Int32, Int32, Float64)
+sum 1, 2, 3, 4.5
+
+
+if a.responds_to?(:abs)
+ # here a's type will be reduced to those responding to the 'abs' method
+end
+
+
+a = some_condition ? 1 : "hello"
+# a : Int32 | String
+
+if a.responds_to?(:abs)
+ # here a will be Int32, since Int32#abs exists but String#abs doesn't
+else
+ # here a will be String
+end
+
+
+if (a = @a).responds_to?(:abs)
+ # here a is guaranteed to respond to `abs`
+end
+
+
+def capture(&block)
+ block
+end
+
+def invoke(&block)
+ block.call
+end
+
+proc = capture { puts "Hello" }
+invoke(&proc) # prints "Hello"
+
+
+
+
+def capture(&block)
+ block
+end
+
+def twice
+ yield
+ yield
+end
+
+proc = capture { puts "Hello" }
+twice &proc
+
+
+twice &->{ puts "Hello" }
+
+
+def say_hello
+ puts "Hello"
+end
+
+twice &->say_hello
+
+
+def foo
+ yield 1
+end
+
+def wrap_foo
+ puts "Before foo"
+ foo do |x|
+ yield x
+ end
+ puts "After foo"
+end
+
+wrap_foo do |i|
+ puts i
+end
+
+
+def foo
+ yield 1
+end
+
+def wrap_foo(&block : Int32 -> _)
+ puts "Before foo"
+ foo(&block)
+ puts "After foo"
+end
+
+wrap_foo do |i|
+ puts i
+end
+
+
+foo_forward do |i|
+ break # error
+end
+
+
+a = 2
+while (a += 1) < 20
+ if a == 10
+ # goes to 'puts a'
+ break
+ end
+end
+puts a #=> 10
+
+
+class Person
+ private def say(message)
+ puts message
+ end
+
+ def say_hello
+ say "hello" # OK, no receiver
+ self.say "hello" # Error, self is a receiver
+
+ other = Person.new "Other"
+ other.say "hello" # Error, other is a receiver
+ end
+end
+
+
+class Employee < Person
+ def say_bye
+ say "bye" # OK
+ end
+end
+
+
+module Namespace
+ class Foo
+ protected def foo
+ puts "Hello"
+ end
+ end
+
+ class Bar
+ def bar
+ # Works, because Foo and Bar are under Namespace
+ Foo.new.foo
+ end
+ end
+end
+
+Namespace::Bar.new.bar
+
+
+class Person
+ protected def self.say(message)
+ puts message
+ end
+
+ def say_hello
+ Person.say "hello"
+ end
+end
+
+
+buffer = uninitialized UInt8[256]
diff --git a/tests/examplefiles/tsql_example.sql b/tests/examplefiles/tsql_example.sql
new file mode 100644
index 00000000..cbd76091
--- /dev/null
+++ b/tests/examplefiles/tsql_example.sql
@@ -0,0 +1,72 @@
+-- Example Transact-SQL file.
+
+-- Single line comment
+/* A comment
+ * spawning two lines. */
+ /* An indented comment
+ * spawning multiple
+ * lines. */
+/* A /* nested */ comment. */
+
+select
+ left(emp.firstname, 1) + '.' + [emp.surname] as "Name",
+ dep.name as [Department]
+into
+ #temp_employee
+from
+ employee as emp
+ inner join department as dep on
+ dep.ident_code = emp.department_id
+where
+ emp.date_of_birth >= '1990-01-01';
+go
+
+declare @TextToFind nvarchar(100) = N'some
+text across
+multiple lines';
+
+set @TextToFind varchar(32) = 'hello' + ' world';
+set @TextTiFind += '!';
+
+declare @Count int = 17 * (3 - 5);
+
+delete from
+ [server].[database].[schema].[table]
+where
+ [Text] = @TextToFind and author Not LIKE '%some%';
+
+goto overthere;
+overthere:
+
+select
+ 123 as "int 1",
+ +123 as "int 2",
+ -123 as "int 3",
+ 0x20 as "hex int",
+ 123.45 as "float 1",
+ -1.23e45 as "float 2"
+ +1.23E+45 as "float 3",
+ -1.23e-45 as "float 4",
+ 1. as "float 5",
+ .1 as "float 6",
+ 1.e2 as "float 7",
+ .1e2 as "float 8";
+
+Select @@Error, $PARTITion.RangePF1(10);
+
+select top 3 Ähnliches from Müll;
+
+-- Example transaction
+BEGIN TRAN
+
+BEGIN TRY
+ INSERT INTO #temp_employe(Name, Department) VALUES ('L. Miller', 'Sales')
+ iNsErT inTO #temp_employe(Name, Department) VaLuEs ('M. Webster', 'Helpdesk')
+ COMMIT TRAN
+END TRY
+BEGIN CATCH
+ print 'cannot perform transaction; rolling back';
+ ROLLBACK TRAN
+END CATCH
+
+-- Comment at end without newline. \ No newline at end of file
diff --git a/tests/test_bibtex.py b/tests/test_bibtex.py
new file mode 100644
index 00000000..3b07d899
--- /dev/null
+++ b/tests/test_bibtex.py
@@ -0,0 +1,236 @@
+# -*- coding: utf-8 -*-
+"""
+ BibTeX Test
+ ~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright 2006-2015 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import textwrap
+import unittest
+
+from pygments.lexers import BibTeXLexer, BSTLexer
+from pygments.token import Token
+
+
+class BibTeXTest(unittest.TestCase):
+ def setUp(self):
+ self.lexer = BibTeXLexer()
+
+ def testPreamble(self):
+ data = u'@PREAMBLE{"% some LaTeX code here"}'
+ tokens = [
+ (Token.Name.Class, u'@PREAMBLE'),
+ (Token.Punctuation, u'{'),
+ (Token.String, u'"'),
+ (Token.String, u'% some LaTeX code here'),
+ (Token.String, u'"'),
+ (Token.Punctuation, u'}'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(list(self.lexer.get_tokens(data)), tokens)
+
+ def testString(self):
+ data = u'@STRING(SCI = "Science")'
+ tokens = [
+ (Token.Name.Class, u'@STRING'),
+ (Token.Punctuation, u'('),
+ (Token.Name.Attribute, u'SCI'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'='),
+ (Token.Text, u' '),
+ (Token.String, u'"'),
+ (Token.String, u'Science'),
+ (Token.String, u'"'),
+ (Token.Punctuation, u')'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(list(self.lexer.get_tokens(data)), tokens)
+
+ def testEntry(self):
+ data = u"""
+ This is a comment.
+
+ @ARTICLE{ruckenstein-diffusion,
+ author = "Liu, Hongquin" # and # "Ruckenstein, Eli",
+ year = 1997,
+ month = JAN,
+ pages = "888-895"
+ }
+ """
+
+ tokens = [
+ (Token.Comment, u'This is a comment.'),
+ (Token.Text, u'\n\n'),
+ (Token.Name.Class, u'@ARTICLE'),
+ (Token.Punctuation, u'{'),
+ (Token.Name.Label, u'ruckenstein-diffusion'),
+ (Token.Punctuation, u','),
+ (Token.Text, u'\n '),
+ (Token.Name.Attribute, u'author'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'='),
+ (Token.Text, u' '),
+ (Token.String, u'"'),
+ (Token.String, u'Liu, Hongquin'),
+ (Token.String, u'"'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'#'),
+ (Token.Text, u' '),
+ (Token.Name.Variable, u'and'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'#'),
+ (Token.Text, u' '),
+ (Token.String, u'"'),
+ (Token.String, u'Ruckenstein, Eli'),
+ (Token.String, u'"'),
+ (Token.Punctuation, u','),
+ (Token.Text, u'\n '),
+ (Token.Name.Attribute, u'year'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'='),
+ (Token.Text, u' '),
+ (Token.Number, u'1997'),
+ (Token.Punctuation, u','),
+ (Token.Text, u'\n '),
+ (Token.Name.Attribute, u'month'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'='),
+ (Token.Text, u' '),
+ (Token.Name.Variable, u'JAN'),
+ (Token.Punctuation, u','),
+ (Token.Text, u'\n '),
+ (Token.Name.Attribute, u'pages'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'='),
+ (Token.Text, u' '),
+ (Token.String, u'"'),
+ (Token.String, u'888-895'),
+ (Token.String, u'"'),
+ (Token.Text, u'\n'),
+ (Token.Punctuation, u'}'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(list(self.lexer.get_tokens(textwrap.dedent(data))), tokens)
+
+ def testComment(self):
+ data = '@COMMENT{test}'
+ tokens = [
+ (Token.Comment, u'@COMMENT'),
+ (Token.Comment, u'{test}'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(list(self.lexer.get_tokens(data)), tokens)
+
+ def testMissingBody(self):
+ data = '@ARTICLE xxx'
+ tokens = [
+ (Token.Name.Class, u'@ARTICLE'),
+ (Token.Text, u' '),
+ (Token.Error, u'x'),
+ (Token.Error, u'x'),
+ (Token.Error, u'x'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(list(self.lexer.get_tokens(data)), tokens)
+
+ def testMismatchedBrace(self):
+ data = '@PREAMBLE(""}'
+ tokens = [
+ (Token.Name.Class, u'@PREAMBLE'),
+ (Token.Punctuation, u'('),
+ (Token.String, u'"'),
+ (Token.String, u'"'),
+ (Token.Error, u'}'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(list(self.lexer.get_tokens(data)), tokens)
+
+
+class BSTTest(unittest.TestCase):
+ def setUp(self):
+ self.lexer = BSTLexer()
+
+ def testBasicBST(self):
+ data = """
+ % BibTeX standard bibliography style `plain'
+
+ INTEGERS { output.state before.all }
+
+ FUNCTION {sort.format.title}
+ { 't :=
+ "A " #2
+ "An " #3
+ "The " #4 t chop.word
+ chop.word
+ chop.word
+ sortify
+ #1 global.max$ substring$
+ }
+
+ ITERATE {call.type$}
+ """
+ tokens = [
+ (Token.Comment.SingleLine, "% BibTeX standard bibliography style `plain'"),
+ (Token.Text, u'\n\n'),
+ (Token.Keyword, u'INTEGERS'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'{'),
+ (Token.Text, u' '),
+ (Token.Name.Variable, u'output.state'),
+ (Token.Text, u' '),
+ (Token.Name.Variable, u'before.all'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'}'),
+ (Token.Text, u'\n\n'),
+ (Token.Keyword, u'FUNCTION'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'{'),
+ (Token.Name.Variable, u'sort.format.title'),
+ (Token.Punctuation, u'}'),
+ (Token.Text, u'\n'),
+ (Token.Punctuation, u'{'),
+ (Token.Text, u' '),
+ (Token.Name.Function, u"'t"),
+ (Token.Text, u' '),
+ (Token.Name.Variable, u':='),
+ (Token.Text, u'\n'),
+ (Token.Literal.String, u'"A "'),
+ (Token.Text, u' '),
+ (Token.Literal.Number, u'#2'),
+ (Token.Text, u'\n '),
+ (Token.Literal.String, u'"An "'),
+ (Token.Text, u' '),
+ (Token.Literal.Number, u'#3'),
+ (Token.Text, u'\n '),
+ (Token.Literal.String, u'"The "'),
+ (Token.Text, u' '),
+ (Token.Literal.Number, u'#4'),
+ (Token.Text, u' '),
+ (Token.Name.Variable, u't'),
+ (Token.Text, u' '),
+ (Token.Name.Variable, u'chop.word'),
+ (Token.Text, u'\n '),
+ (Token.Name.Variable, u'chop.word'),
+ (Token.Text, u'\n'),
+ (Token.Name.Variable, u'chop.word'),
+ (Token.Text, u'\n'),
+ (Token.Name.Variable, u'sortify'),
+ (Token.Text, u'\n'),
+ (Token.Literal.Number, u'#1'),
+ (Token.Text, u' '),
+ (Token.Name.Builtin, u'global.max$'),
+ (Token.Text, u' '),
+ (Token.Name.Builtin, u'substring$'),
+ (Token.Text, u'\n'),
+ (Token.Punctuation, u'}'),
+ (Token.Text, u'\n\n'),
+ (Token.Keyword, u'ITERATE'),
+ (Token.Text, u' '),
+ (Token.Punctuation, u'{'),
+ (Token.Name.Builtin, u'call.type$'),
+ (Token.Punctuation, u'}'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(list(self.lexer.get_tokens(textwrap.dedent(data))), tokens)
diff --git a/tests/test_crystal.py b/tests/test_crystal.py
new file mode 100644
index 00000000..9a1588f2
--- /dev/null
+++ b/tests/test_crystal.py
@@ -0,0 +1,308 @@
+# -*- coding: utf-8 -*-
+"""
+ Basic CrystalLexer Test
+ ~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright 2006-2016 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from __future__ import unicode_literals
+import unittest
+
+from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
+ Number, Punctuation, Error
+from pygments.lexers import CrystalLexer
+
+
+class CrystalTest(unittest.TestCase):
+
+ def setUp(self):
+ self.lexer = CrystalLexer()
+ self.maxDiff = None
+
+ def testRangeSyntax1(self):
+ fragment = '1...3\n'
+ tokens = [
+ (Number.Integer, '1'),
+ (Operator, '...'),
+ (Number.Integer, '3'),
+ (Text, '\n'),
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
+
+ def testRangeSyntax2(self):
+ fragment = '1 .. 3\n'
+ tokens = [
+ (Number.Integer, '1'),
+ (Text, ' '),
+ (Operator, '..'),
+ (Text, ' '),
+ (Number.Integer, '3'),
+ (Text, '\n'),
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
+
+ def testInterpolationNestedCurly(self):
+ fragment = (
+ '"A#{ (3..5).group_by { |x| x/2}.map '
+ 'do |k,v| "#{k}" end.join }" + "Z"\n')
+ tokens = [
+ (String.Double, '"'),
+ (String.Double, 'A'),
+ (String.Interpol, '#{'),
+ (Text, ' '),
+ (Punctuation, '('),
+ (Number.Integer, '3'),
+ (Operator, '..'),
+ (Number.Integer, '5'),
+ (Punctuation, ')'),
+ (Operator, '.'),
+ (Name, 'group_by'),
+ (Text, ' '),
+ (String.Interpol, '{'),
+ (Text, ' '),
+ (Operator, '|'),
+ (Name, 'x'),
+ (Operator, '|'),
+ (Text, ' '),
+ (Name, 'x'),
+ (Operator, '/'),
+ (Number.Integer, '2'),
+ (String.Interpol, '}'),
+ (Operator, '.'),
+ (Name, 'map'),
+ (Text, ' '),
+ (Keyword, 'do'),
+ (Text, ' '),
+ (Operator, '|'),
+ (Name, 'k'),
+ (Punctuation, ','),
+ (Name, 'v'),
+ (Operator, '|'),
+ (Text, ' '),
+ (String.Double, '"'),
+ (String.Interpol, '#{'),
+ (Name, 'k'),
+ (String.Interpol, '}'),
+ (String.Double, '"'),
+ (Text, ' '),
+ (Keyword, 'end'),
+ (Operator, '.'),
+ (Name, 'join'),
+ (Text, ' '),
+ (String.Interpol, '}'),
+ (String.Double, '"'),
+ (Text, ' '),
+ (Operator, '+'),
+ (Text, ' '),
+ (String.Double, '"'),
+ (String.Double, 'Z'),
+ (String.Double, '"'),
+ (Text, '\n'),
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
+
+ def testOperatorMethods(self):
+ fragment = '([] of Int32).[]?(5)\n'
+ tokens = [
+ (Punctuation, '('),
+ (Operator, '['),
+ (Operator, ']'),
+ (Text, ' '),
+ (Keyword, 'of'),
+ (Text, ' '),
+ (Name.Builtin, 'Int32'),
+ (Punctuation, ')'),
+ (Operator, '.'),
+ (Name.Operator, '[]?'),
+ (Punctuation, '('),
+ (Number.Integer, '5'),
+ (Punctuation, ')'),
+ (Text, '\n')
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
+
+ def testArrayAccess(self):
+ fragment = '[5][5]?\n'
+ tokens = [
+ (Operator, '['),
+ (Number.Integer, '5'),
+ (Operator, ']'),
+ (Operator, '['),
+ (Number.Integer, '5'),
+ (Operator, ']?'),
+ (Text, '\n')
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
+
+ def testNumbers(self):
+ for kind, testset in [
+ (Number.Integer, '0 1 1_000_000 1u8 11231231231121312i64'),
+ (Number.Float, '0.0 1.0_f32 1_f32 0f64 1e+4 1e111 1_234.567_890'),
+ (Number.Bin, '0b1001_0110 0b0u8'),
+ (Number.Oct, '0o17 0o7_i32'),
+ (Number.Hex, '0xdeadBEEF'),
+ ]:
+ for fragment in testset.split():
+ self.assertEqual([(kind, fragment), (Text, '\n')],
+ list(self.lexer.get_tokens(fragment + '\n')))
+
+ for fragment in '01 0b2 0x129g2 0o12358'.split():
+ self.assertEqual(next(self.lexer.get_tokens(fragment + '\n'))[0],
+ Error)
+
+ def testChars(self):
+ for fragment in ["'a'", "'я'", "'\\u{1234}'", "'\n'"]:
+ self.assertEqual([(String.Char, fragment), (Text, '\n')],
+ list(self.lexer.get_tokens(fragment + '\n')))
+ self.assertEqual(next(self.lexer.get_tokens("'abc'"))[0], Error)
+
+ def testMacro(self):
+ fragment = (
+ 'def<=>(other : self) : Int\n'
+ '{%for field in %w(first_name middle_name last_name)%}\n'
+ 'cmp={{field.id}}<=>other.{{field.id}}\n'
+ 'return cmp if cmp!=0\n'
+ '{%end%}\n'
+ '0\n'
+ 'end\n')
+ tokens = [
+ (Keyword, 'def'),
+ (Name.Function, '<=>'),
+ (Punctuation, '('),
+ (Name, 'other'),
+ (Text, ' '),
+ (Punctuation, ':'),
+ (Text, ' '),
+ (Keyword.Pseudo, 'self'),
+ (Punctuation, ')'),
+ (Text, ' '),
+ (Punctuation, ':'),
+ (Text, ' '),
+ (Name.Builtin, 'Int'),
+ (Text, '\n'),
+ (String.Interpol, '{%'),
+ (Keyword, 'for'),
+ (Text, ' '),
+ (Name, 'field'),
+ (Text, ' '),
+ (Keyword, 'in'),
+ (Text, ' '),
+ (String.Other, '%w('),
+ (String.Other, 'first_name middle_name last_name'),
+ (String.Other, ')'),
+ (String.Interpol, '%}'),
+ (Text, '\n'),
+ (Name, 'cmp'),
+ (Operator, '='),
+ (String.Interpol, '{{'),
+ (Name, 'field'),
+ (Operator, '.'),
+ (Name, 'id'),
+ (String.Interpol, '}}'),
+ (Operator, '<=>'),
+ (Name, 'other'),
+ (Operator, '.'),
+ (String.Interpol, '{{'),
+ (Name, 'field'),
+ (Operator, '.'),
+ (Name, 'id'),
+ (String.Interpol, '}}'),
+ (Text, '\n'),
+ (Keyword, 'return'),
+ (Text, ' '),
+ (Name, 'cmp'),
+ (Text, ' '),
+ (Keyword, 'if'),
+ (Text, ' '),
+ (Name, 'cmp'),
+ (Operator, '!='),
+ (Number.Integer, '0'),
+ (Text, '\n'),
+ (String.Interpol, '{%'),
+ (Keyword, 'end'),
+ (String.Interpol, '%}'),
+ (Text, '\n'),
+ (Number.Integer, '0'),
+ (Text, '\n'),
+ (Keyword, 'end'),
+ (Text, '\n')
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
+
+ def testLib(self):
+ fragment = (
+ '@[Link("some")]\nlib LibSome\n'
+ '@[CallConvention("X86_StdCall")]\nfun foo="some.foo"(thing : Void*) : LibC::Int\n'
+ 'end\n')
+ tokens = [
+ (Operator, '@['),
+ (Name.Decorator, 'Link'),
+ (Punctuation, '('),
+ (String.Double, '"'),
+ (String.Double, 'some'),
+ (String.Double, '"'),
+ (Punctuation, ')'),
+ (Operator, ']'),
+ (Text, '\n'),
+ (Keyword, 'lib'),
+ (Text, ' '),
+ (Name.Namespace, 'LibSome'),
+ (Text, '\n'),
+ (Operator, '@['),
+ (Name.Decorator, 'CallConvention'),
+ (Punctuation, '('),
+ (String.Double, '"'),
+ (String.Double, 'X86_StdCall'),
+ (String.Double, '"'),
+ (Punctuation, ')'),
+ (Operator, ']'),
+ (Text, '\n'),
+ (Keyword, 'fun'),
+ (Text, ' '),
+ (Name.Function, 'foo'),
+ (Operator, '='),
+ (String.Double, '"'),
+ (String.Double, 'some.foo'),
+ (String.Double, '"'),
+ (Punctuation, '('),
+ (Name, 'thing'),
+ (Text, ' '),
+ (Punctuation, ':'),
+ (Text, ' '),
+ (Name.Builtin, 'Void'),
+ (Operator, '*'),
+ (Punctuation, ')'),
+ (Text, ' '),
+ (Punctuation, ':'),
+ (Text, ' '),
+ (Name, 'LibC'),
+ (Operator, '::'),
+ (Name.Builtin, 'Int'),
+ (Text, '\n'),
+ (Keyword, 'end'),
+ (Text, '\n')
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
+
+ def testEscapedBracestring(self):
+ fragment = 'str.gsub(%r{\\\\\\\\}, "/")\n'
+ tokens = [
+ (Name, 'str'),
+ (Operator, '.'),
+ (Name, 'gsub'),
+ (Punctuation, '('),
+ (String.Regex, '%r{'),
+ (String.Regex, '\\\\'),
+ (String.Regex, '\\\\'),
+ (String.Regex, '}'),
+ (Punctuation, ','),
+ (Text, ' '),
+ (String.Double, '"'),
+ (String.Double, '/'),
+ (String.Double, '"'),
+ (Punctuation, ')'),
+ (Text, '\n'),
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
diff --git a/tests/test_sql.py b/tests/test_sql.py
new file mode 100644
index 00000000..c5f5c758
--- /dev/null
+++ b/tests/test_sql.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+"""
+ Pygments SQL lexers tests
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright 2006-2016 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+import unittest
+
+from pygments.lexers.sql import TransactSqlLexer
+from pygments.token import Comment, Name, Number, Punctuation, Whitespace
+
+
+class TransactSqlLexerTest(unittest.TestCase):
+
+ def setUp(self):
+ self.lexer = TransactSqlLexer()
+
+ def _assertAreTokensOfType(self, examples, expected_token_type):
+ for test_number, example in enumerate(examples.split(), 1):
+ token_count = 0
+ for token_type, token_value in self.lexer.get_tokens(example):
+ if token_type != Whitespace:
+ token_count += 1
+ self.assertEqual(
+ token_type, expected_token_type,
+ 'token_type #%d for %s is be %s but must be %s' %
+ (test_number, token_value, token_type, expected_token_type))
+ self.assertEqual(
+ token_count, 1,
+ '%s must yield exactly 1 token instead of %d' %
+ (example, token_count))
+
+ def _assertTokensMatch(self, text, expected_tokens_without_trailing_newline):
+ actual_tokens = tuple(self.lexer.get_tokens(text))
+ if (len(actual_tokens) >= 1) and (actual_tokens[-1] == (Whitespace, '\n')):
+ actual_tokens = tuple(actual_tokens[:-1])
+ self.assertEqual(
+ expected_tokens_without_trailing_newline, actual_tokens,
+ 'text must yield expected tokens: %s' % text)
+
+ def test_can_lex_float(self):
+ self._assertAreTokensOfType(
+ '1. 1.e1 .1 1.2 1.2e3 1.2e+3 1.2e-3 1e2', Number.Float)
+ self._assertTokensMatch(
+ '1e2.1e2',
+ ((Number.Float, '1e2'), (Number.Float, '.1e2'))
+ )
+
+ def test_can_reject_almost_float(self):
+ self._assertTokensMatch(
+ '.e1',
+ ((Punctuation, '.'), (Name, 'e1')))
+
+ def test_can_lex_integer(self):
+ self._assertAreTokensOfType(
+ '1 23 456', Number.Integer)
+
+ def test_can_lex_names(self):
+ self._assertAreTokensOfType(
+ u'thingy thingy123 _thingy _ _123 Ähnliches Müll #temp1 ##temp2', Name)
+
+ def test_can_lex_comments(self):
+ self._assertTokensMatch('--\n', ((Comment.Single, '--\n'),))
+ self._assertTokensMatch('/**/', (
+ (Comment.Multiline, '/*'), (Comment.Multiline, '*/')
+ ))
+ self._assertTokensMatch('/*/**/*/', (
+ (Comment.Multiline, '/*'),
+ (Comment.Multiline, '/*'),
+ (Comment.Multiline, '*/'),
+ (Comment.Multiline, '*/'),
+ ))
diff --git a/tests/test_whiley.py b/tests/test_whiley.py
new file mode 100644
index 00000000..2e957875
--- /dev/null
+++ b/tests/test_whiley.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+"""
+ Whiley Test
+ ~~~~~~~~~~~
+
+ :copyright: Copyright 2006-2016 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import unittest
+
+from pygments.lexers import WhileyLexer
+from pygments.token import Token
+
+
+class WhileyTest(unittest.TestCase):
+ def setUp(self):
+ self.lexer = WhileyLexer()
+
+ def testNeedsName(self):
+ fragment = u'123 \u2200 x\n'
+ tokens = [
+ (Token.Literal.Number.Integer, u'123'),
+ (Token.Text, u' '),
+ (Token.Operator, u'\u2200'),
+ (Token.Text, u' '),
+ (Token.Name, u'x'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))