summaryrefslogtreecommitdiffstats
path: root/runtime/syntax/ocaml.vim
blob: 04ba39203df0e90a60dc95179e51c682710198b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
" Vim syntax file
" Language:     OCaml
" Filenames:    *.ml *.mli *.mll *.mly
" Maintainers:  Markus Mottl      <markus.mottl@gmail.com>
"               Karl-Heinz Sylla  <Karl-Heinz.Sylla@gmd.de>
"               Issac Trotts      <ijtrotts@ucdavis.edu>
" URL:          https://github.com/ocaml/vim-ocaml
" Last Change:
"               2019 Nov 05 - Accurate type highlighting (Maëlan)
"               2018 Nov 08 - Improved highlighting of operators (Maëlan)
"               2018 Apr 22 - Improved support for PPX (Andrey Popp)
"               2018 Mar 16 - Remove raise, lnot and not from keywords (Étienne Millon, "copy")
"               2017 Apr 11 - Improved matching of negative numbers (MM)
"               2016 Mar 11 - Improved support for quoted strings (Glen Mével)
"               2015 Aug 13 - Allow apostrophes in identifiers (Jonathan Chan, Einar Lielmanis)
"               2015 Jun 17 - Added new "nonrec" keyword (MM)

" A minor patch was applied to the official version so that object/end
" can be distinguished from begin/end, which is used for indentation,
" and folding. (David Baelde)

" Quit when a syntax file was already loaded
if exists("b:current_syntax") && b:current_syntax == "ocaml"
  finish
endif

let s:keepcpo = &cpo
set cpo&vim

" ' can be used in OCaml identifiers
setlocal iskeyword+='

" ` is part of the name of polymorphic variants
setlocal iskeyword+=`

" OCaml is case sensitive.
syn case match

" Access to the method of an object
syn match    ocamlMethod       "#"

" Scripting directives
syn match    ocamlScript "^#\<\(quit\|labels\|warnings\|warn_error\|directory\|remove_directory\|cd\|load\|load_rec\|use\|mod_use\|install_printer\|remove_printer\|require\|list\|ppx\|principal\|predicates\|rectypes\|thread\|trace\|untrace\|untrace_all\|print_depth\|print_length\|camlp4o\|camlp4r\|topfind_log\|topfind_verbose\)\>"

" lowercase identifier - the standard way to match
syn match    ocamlLCIdentifier /\<\(\l\|_\)\(\w\|'\)*\>/

" Errors
syn match    ocamlBraceErr   "}"
syn match    ocamlBrackErr   "\]"
syn match    ocamlParenErr   ")"
syn match    ocamlArrErr     "|]"

syn match    ocamlCountErr   "\<downto\>"
syn match    ocamlCountErr   "\<to\>"

if !exists("ocaml_revised")
  syn match    ocamlDoErr      "\<do\>"
endif

syn match    ocamlDoneErr    "\<done\>"
syn match    ocamlThenErr    "\<then\>"

" Error-highlighting of "end" without synchronization:
" as keyword or as error (default)
if exists("ocaml_noend_error")
  syn match    ocamlKeyword    "\<end\>"
else
  syn match    ocamlEndErr     "\<end\>"
endif

" These keywords are only expected nested in constructions that are handled by
" the type linter, so outside of type contexts we highlight them as errors:
syn match    ocamlKwErr  "\<\(mutable\|nonrec\|of\|private\)\>"

" Some convenient clusters
syn cluster  ocamlAllErrs contains=@ocamlAENoParen,ocamlParenErr
syn cluster  ocamlAENoParen contains=ocamlBraceErr,ocamlBrackErr,ocamlCountErr,ocamlDoErr,ocamlDoneErr,ocamlEndErr,ocamlThenErr,ocamlKwErr

syn cluster  ocamlContained contains=ocamlTodo,ocamlPreDef,ocamlModParam,ocamlModParam1,ocamlModTypePre,ocamlModRHS,ocamlFuncWith,ocamlModTypeRestr,ocamlModTRWith,ocamlWith,ocamlWithRest,ocamlFullMod,ocamlVal


" Enclosing delimiters
syn region   ocamlNone transparent matchgroup=ocamlEncl start="(" matchgroup=ocamlEncl end=")" contains=ALLBUT,@ocamlContained,ocamlParenErr
syn region   ocamlNone transparent matchgroup=ocamlEncl start="{" matchgroup=ocamlEncl end="}"  contains=ALLBUT,@ocamlContained,ocamlBraceErr
syn region   ocamlNone transparent matchgroup=ocamlEncl start="\[" matchgroup=ocamlEncl end="\]" contains=ALLBUT,@ocamlContained,ocamlBrackErr
syn region   ocamlNone transparent matchgroup=ocamlEncl start="\[|" matchgroup=ocamlEncl end="|\]" contains=ALLBUT,@ocamlContained,ocamlArrErr


" Comments
syn region   ocamlComment start="(\*" end="\*)" contains=@Spell,ocamlComment,ocamlTodo
syn keyword  ocamlTodo contained TODO FIXME XXX NOTE


" Objects
syn region   ocamlEnd matchgroup=ocamlObject start="\<object\>" matchgroup=ocamlObject end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr


" Blocks
if !exists("ocaml_revised")
  syn region   ocamlEnd matchgroup=ocamlKeyword start="\<begin\>" matchgroup=ocamlKeyword end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr
endif


" "for"
syn region   ocamlNone matchgroup=ocamlKeyword start="\<for\>" matchgroup=ocamlKeyword end="\<\(to\|downto\)\>" contains=ALLBUT,@ocamlContained,ocamlCountErr


" "do"
if !exists("ocaml_revised")
  syn region   ocamlDo matchgroup=ocamlKeyword start="\<do\>" matchgroup=ocamlKeyword end="\<done\>" contains=ALLBUT,@ocamlContained,ocamlDoneErr
endif

" "if"
syn region   ocamlNone matchgroup=ocamlKeyword start="\<if\>" matchgroup=ocamlKeyword end="\<then\>" contains=ALLBUT,@ocamlContained,ocamlThenErr

"" PPX nodes

syn match ocamlPpxIdentifier /\(\[@\{1,3\}\)\@<=\w\+\(\.\w\+\)*/
syn region ocamlPpx matchgroup=ocamlPpxEncl start="\[@\{1,3\}" contains=TOP end="\]"

"" Modules

" "open"
syn match   ocamlKeyword "\<open\>" skipwhite skipempty nextgroup=ocamlFullMod

" "include"
syn match    ocamlKeyword "\<include\>" skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod

" "module" - somewhat complicated stuff ;-)
" 2022-10: please document it?
syn region   ocamlModule matchgroup=ocamlKeyword start="\<module\>" matchgroup=ocamlModule end="\<_\|\u\(\w\|'\)*\>" contains=@ocamlAllErrs,ocamlComment skipwhite skipempty nextgroup=ocamlPreDef
syn region   ocamlPreDef start="."me=e-1 end="[a-z:=)]\@=" contained contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod,ocamlModTypeRestr nextgroup=ocamlModTypePre,ocamlModPreRHS
syn region   ocamlModParam start="(\*\@!" end=")" contained contains=ocamlGenMod,ocamlModParam,ocamlModParam1,ocamlSig,ocamlVal
syn match    ocamlModParam1 "\<\u\(\w\|'\)*\>" contained skipwhite skipempty
syn match    ocamlGenMod "()" contained skipwhite skipempty

syn match    ocamlModTypePre ":" contained skipwhite skipempty nextgroup=ocamlModTRWith,ocamlSig,ocamlFunctor,ocamlModTypeRestr,ocamlModTypeOf
syn match    ocamlModTypeRestr "\<\w\(\w\|'\)*\( *\. *\w\(\w\|'\)*\)*\>" contained

syn match    ocamlModPreRHS "=" contained skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod
syn keyword  ocamlKeyword val
syn region   ocamlVal matchgroup=ocamlKeyword start="\<val\>" matchgroup=ocamlLCIdentifier end="\<\l\(\w\|'\)*\>" contains=@ocamlAllErrs,ocamlComment,ocamlFullMod skipwhite skipempty nextgroup=ocamlModTypePre
syn region   ocamlModRHS start="." end=". *\w\|([^*]"me=e-2 contained contains=ocamlComment skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod
syn match    ocamlFullMod "\<\u\(\w\|'\)*\( *\. *\u\(\w\|'\)*\)*" contained skipwhite skipempty nextgroup=ocamlFuncWith

syn region   ocamlFuncWith start="([*)]\@!" end=")" contained contains=ocamlComment,ocamlWith,ocamlStruct skipwhite skipempty nextgroup=ocamlFuncWith

syn region   ocamlModTRWith start="(\*\@!" end=")" contained contains=@ocamlAENoParen,ocamlWith
syn match    ocamlWith "\<\(\u\(\w\|'\)* *\. *\)*\w\(\w\|'\)*\>" contained skipwhite skipempty nextgroup=ocamlWithRest
syn region   ocamlWithRest start="[^)]" end=")"me=e-1 contained contains=ALLBUT,@ocamlContained

" "struct"
syn region   ocamlStruct matchgroup=ocamlStructEncl start="\<\(module\s\+\)\=struct\>" matchgroup=ocamlStructEncl end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr

" "sig"
syn region   ocamlSig matchgroup=ocamlSigEncl start="\<sig\>" matchgroup=ocamlSigEncl end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr

" "functor"
syn region   ocamlFunctor start="\<functor\>" matchgroup=ocamlKeyword end="->" contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod skipwhite skipempty nextgroup=ocamlStruct,ocamlSig,ocamlFuncWith,ocamlFunctor

" "module type"
syn region   ocamlModTypeOf start="\<module\s\+type\(\s\+of\)\=\>" matchgroup=ocamlModule end="\<\w\(\w\|'\)*\>" contains=ocamlComment skipwhite skipempty nextgroup=ocamlMTDef
syn match    ocamlMTDef "=\s*\w\(\w\|'\)*\>"hs=s+1,me=s+1 skipwhite skipempty nextgroup=ocamlFullMod

" Quoted strings
syn region ocamlString matchgroup=ocamlQuotedStringDelim start="{\z\([a-z_]*\)|" end="|\z1}" contains=@Spell
syn region ocamlString matchgroup=ocamlQuotedStringDelim start="{%[a-z_]\+\(\.[a-z_]\+\)\?\( \z\([a-z_]\+\)\)\?|" end="|\z1}" contains=@Spell

syn keyword  ocamlKeyword  and as assert class
syn keyword  ocamlKeyword  else
syn keyword  ocamlKeyword  external
syn keyword  ocamlKeyword  in inherit initializer
syn keyword  ocamlKeyword  lazy let match
syn keyword  ocamlKeyword  method new
syn keyword  ocamlKeyword  parser rec
syn keyword  ocamlKeyword  try
syn keyword  ocamlKeyword  virtual when while with

" Keywords which are handled by the type linter:
"     as (within a type equation)
"     constraint exception mutable nonrec of private type

" The `fun` keyword has special treatment because of the syntax `fun … : t -> e`
" where `->` ends the type context rather than being part of it; to handle that,
" we blacklist the ocamlTypeAnnot matchgroup, and we plug ocamlFunTypeAnnot
" instead (later in this file, by using containedin=ocamlFun):
syn region ocamlFun matchgroup=ocamlKeyword start='\<fun\>' matchgroup=ocamlArrow end='->'
\ contains=ALLBUT,@ocamlContained,ocamlArrow,ocamlInfixOp,ocamlTypeAnnot

if exists("ocaml_revised")
  syn keyword  ocamlKeyword  do value
  syn keyword  ocamlBoolean  True False
else
  syn keyword  ocamlKeyword  function
  syn keyword  ocamlBoolean  true false
endif

syn match    ocamlEmptyConstructor  "(\s*)"
syn match    ocamlEmptyConstructor  "\[\s*\]"
syn match    ocamlEmptyConstructor  "\[|\s*>|]"
syn match    ocamlEmptyConstructor  "\[<\s*>\]"
syn match    ocamlConstructor  "\u\(\w\|'\)*\>"

" Polymorphic variants
syn match    ocamlConstructor  "`\w\(\w\|'\)*\>"

" Module prefix
syn match    ocamlModPath      "\u\(\w\|'\)* *\."he=e-1

syn match    ocamlCharacter    "'\\\d\d\d'\|'\\[\'ntbr]'\|'.'"
syn match    ocamlCharacter    "'\\x\x\x'"
syn match    ocamlCharErr      "'\\\d\d'\|'\\\d'"
syn match    ocamlCharErr      "'\\[^\'ntbr]'"
syn region   ocamlString       start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell

syn match    ocamlAnyVar       "\<_\>"
syn match    ocamlKeyChar      "|]\@!"
syn match    ocamlKeyChar      ";"
syn match    ocamlKeyChar      "\~"
syn match    ocamlKeyChar      "?"

" NOTE: for correct precedence, the rule for ";;" must come after that for ";"
syn match    ocamlTopStop      ";;"

"" Operators

" The grammar of operators is found there:
"     https://caml.inria.fr/pub/docs/manual-ocaml/names.html#operator-name
"     https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s:ext-ops
"     https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s:index-operators
" = is both an operator name and a keyword, we let the user choose how
" to display it (has to be declared before regular infix operators):
syn match    ocamlEqual        "="
" Custom indexing operators:
syn region   ocamlIndexing matchgroup=ocamlIndexingOp
  \ start="\.[~?!:|&$%=>@^/*+-][~?!.:|&$%<=>@^*/+-]*\_s*("
  \ end=")\(\_s*<-\)\?"
  \ contains=ALLBUT,@ocamlContained,ocamlParenErr
syn region   ocamlIndexing matchgroup=ocamlIndexingOp
  \ start="\.[~?!:|&$%=>@^/*+-][~?!.:|&$%<=>@^*/+-]*\_s*\["
  \ end="]\(\_s*<-\)\?"
  \ contains=ALLBUT,@ocamlContained,ocamlBrackErr
syn region   ocamlIndexing matchgroup=ocamlIndexingOp
  \ start="\.[~?!:|&$%=>@^/*+-][~?!.:|&$%<=>@^*/+-]*\_s*{"
  \ end="}\(\_s*<-\)\?"
  \ contains=ALLBUT,@ocamlContained,ocamlBraceErr
" Extension operators (has to be declared before regular infix operators):
syn match    ocamlExtensionOp          "#[#~?!.:|&$%<=>@^*/+-]\+"
" Infix and prefix operators:
syn match    ocamlPrefixOp              "![~?!.:|&$%<=>@^*/+-]*"
syn match    ocamlPrefixOp           "[~?][~?!.:|&$%<=>@^*/+-]\+"
syn match    ocamlInfixOp   "[&$%<>@^*/+-][~?!.:|&$%<=>@^*/+-]*"
syn match    ocamlInfixOp            "[|=][~?!.:|&$%<=>@^*/+-]\+"
syn match    ocamlInfixOp               "#[~?!.:|&$%<=>@^*/+-]\+#\@!"
syn match    ocamlInfixOp              "!=[~?!.:|&$%<=>@^*/+-]\@!"
syn keyword  ocamlInfixOpKeyword      asr land lor lsl lsr lxor mod or
" := is technically an infix operator, but we may want to show it as a keyword
" (somewhat analogously to = for let‐bindings and <- for assignations):
syn match    ocamlRefAssign    ":="
" :: is technically not an operator, but we may want to show it as such:
syn match    ocamlCons         "::"
" -> and <- are keywords, not operators (but can appear in longer operators):
syn match    ocamlArrow        "->[~?!.:|&$%<=>@^*/+-]\@!"
if exists("ocaml_revised")
  syn match    ocamlErr        "<-[~?!.:|&$%<=>@^*/+-]\@!"
else
  syn match    ocamlKeyChar    "<-[~?!.:|&$%<=>@^*/+-]\@!"
endif

" Script shebang (has to be declared after operators)
syn match    ocamlShebang       "\%1l^#!.*$"

syn match    ocamlNumber        "-\=\<\d\(_\|\d\)*[l|L|n]\?\>"
syn match    ocamlNumber        "-\=\<0[x|X]\(\x\|_\)\+[l|L|n]\?\>"
syn match    ocamlNumber        "-\=\<0[o|O]\(\o\|_\)\+[l|L|n]\?\>"
syn match    ocamlNumber        "-\=\<0[b|B]\([01]\|_\)\+[l|L|n]\?\>"
syn match    ocamlFloat         "-\=\<\d\(_\|\d\)*\.\?\(_\|\d\)*\([eE][-+]\=\d\(_\|\d\)*\)\=\>"

" Labels
syn match    ocamlLabel        "[~?]\(\l\|_\)\(\w\|'\)*:\?"
syn region   ocamlLabel transparent matchgroup=ocamlLabel start="[~?](\(\l\|_\)\(\w\|'\)*"lc=2 end=")"me=e-1 contains=ALLBUT,@ocamlContained,ocamlParenErr

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""&q