Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds a lexer for the MiniZinc language. * Shorten link * Simplify ID regex * Remove unnecessary newline rule * Simplify single comment rule * Change priority of generic identifier rule * Remove unnecessary parentheses
- Loading branch information
1 parent
be51612
commit d318419
Showing
4 changed files
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
% from MiniZinc Handbook: | ||
% https://www.minizinc.org/doc-latest/en/modelling.html | ||
|
||
% Colouring Australia using nc colours | ||
int: nc = 3; | ||
|
||
var 1..nc: wa; var 1..nc: nt; var 1..nc: sa; var 1..nc: q; | ||
var 1..nc: nsw; var 1..nc: v; var 1..nc: t; | ||
|
||
constraint wa != nt; | ||
constraint wa != sa; | ||
constraint nt != sa; | ||
constraint nt != q; | ||
constraint sa != q; | ||
constraint sa != nsw; | ||
constraint sa != v; | ||
constraint q != nsw; | ||
constraint nsw != v; | ||
solve satisfy; | ||
|
||
output ["wa=\(wa)\t nt=\(nt)\t sa=\(sa)\n", | ||
"q=\(q)\t nsw=\(nsw)\t v=\(v)\n", | ||
"t=", show(t), "\n"]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# -*- coding: utf-8 -*- # | ||
# frozen_string_literal: true | ||
|
||
# Based on Chroma's MiniZinc lexer: | ||
# https://github.com/alecthomas/chroma/blob/5152194c717b394686d3d7a7e1946a360ec0728f/lexers/m/minizinc.go | ||
|
||
module Rouge | ||
module Lexers | ||
class MiniZinc < RegexLexer | ||
title "MiniZinc" | ||
desc "MiniZinc is a free and open-source constraint modeling language (minizinc.org)" | ||
tag 'minizinc' | ||
filenames '*.mzn', '*.fzn', '*.dzn' | ||
mimetypes 'text/minizinc' | ||
|
||
def self.builtins | ||
@builtins = Set.new %w[ | ||
abort abs acosh array_intersect array_union array1d array2d array3d | ||
array4d array5d array6d asin assert atan bool2int card ceil concat | ||
cos cosh dom dom_array dom_size fix exp floor index_set | ||
index_set_1of2 index_set_2of2 index_set_1of3 index_set_2of3 | ||
index_set_3of3 int2float is_fixed join lb lb_array length ln log log2 | ||
log10 min max pow product round set2array show show_int show_float | ||
sin sinh sqrt sum tan tanh trace ub ub_array | ||
] | ||
end | ||
|
||
def self.keywords | ||
@keywords = Set.new %w[ | ||
ann annotation any constraint else endif function for forall if | ||
include list of op output minimize maximize par predicate record | ||
satisfy solve test then type var where | ||
] | ||
end | ||
|
||
def self.keywords_type | ||
@keywords_type ||= Set.new %w( | ||
array set bool enum float int string tuple | ||
) | ||
end | ||
|
||
def self.operators | ||
@operators ||= Set.new %w( | ||
in subset superset union diff symdiff intersect | ||
) | ||
end | ||
|
||
id = /[$a-zA-Z_]\w*/ | ||
|
||
state :root do | ||
rule %r(\s+)m, Text::Whitespace | ||
rule %r(\\\n)m, Text::Whitespace | ||
rule %r(%.*), Comment::Single | ||
rule %r(/(\\\n)?[*](.|\n)*?[*](\\\n)?/)m, Comment::Multiline | ||
rule %r/"(\\\\|\\"|[^"])*"/, Literal::String | ||
|
||
rule %r(not|<->|->|<-|\\/|xor|/\\), Operator | ||
rule %r(<|>|<=|>=|==|=|!=), Operator | ||
rule %r(\+|-|\*|/|div|mod), Operator | ||
rule %r(\\|\.\.|\+\+), Operator | ||
rule %r([|()\[\]{},:;]), Punctuation | ||
rule %r((true|false)\b), Keyword::Constant | ||
rule %r(([+-]?)\d+(\.(?!\.)\d*)?([eE][-+]?\d+)?), Literal::Number | ||
|
||
rule id do |m| | ||
if self.class.keywords.include? m[0] | ||
token Keyword | ||
elsif self.class.keywords_type.include? m[0] | ||
token Keyword::Type | ||
elsif self.class.builtins.include? m[0] | ||
token Name::Builtin | ||
elsif self.class.operators.include? m[0] | ||
token Operator | ||
else | ||
token Name::Other | ||
end | ||
end | ||
|
||
rule %r(::\s*([^\W\d]\w*)(\s*\([^\)]*\))?), Name::Decorator | ||
rule %r(\b([^\W\d]\w*)\b(\()) do | ||
groups Name::Function, Punctuation | ||
end | ||
rule %r([^\W\d]\w*), Name::Other | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# -*- coding: utf-8 -*- # | ||
# frozen_string_literal: true | ||
|
||
describe Rouge::Lexers::MiniZinc do | ||
let(:subject) { Rouge::Lexers::MiniZinc.new } | ||
|
||
describe 'guessing' do | ||
include Support::Guessing | ||
|
||
it 'guesses by filename' do | ||
assert_guess :filename => 'foo.mzn' | ||
assert_guess :filename => 'foo.fzn' | ||
assert_guess :filename => 'foo.dzn' | ||
end | ||
|
||
it 'guesses by mimetype' do | ||
assert_guess :mimetype => 'text/minizinc' | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
% from MiniZinc Handbook: | ||
% https://www.minizinc.org/doc-latest/en/predicates.html | ||
|
||
% Simple nurse rostering | ||
include "regular.mzn"; | ||
enum NURSE; | ||
enum DAY; | ||
int: req_day; | ||
int: req_night; | ||
int: min_night; | ||
|
||
enum SHIFT = { d, n, o }; | ||
int: S = card(SHIFT); | ||
|
||
int: Q = 6; int: q0 = 1; set of int: STATE = 1..Q; | ||
array[STATE,SHIFT] of int: t = | ||
[| 2, 3, 1 % state 1 | ||
| 4, 4, 1 % state 2 | ||
| 4, 5, 1 % state 3 | ||
| 6, 6, 1 % state 4 | ||
| 6, 0, 1 % state 5 | ||
| 0, 0, 1|]; % state 6 | ||
|
||
array[NURSE,DAY] of var SHIFT: roster; | ||
|
||
constraint forall(j in DAY)( | ||
sum(i in NURSE)(roster[i,j] == d) == req_day /\ | ||
sum(i in NURSE)(roster[i,j] == n) == req_night | ||
); | ||
constraint forall(i in NURSE)( | ||
regular([roster[i,j] | j in DAY], Q, S, t, q0, STATE) /\ | ||
sum(j in DAY)(roster[i,j] == n) >= min_night | ||
); | ||
|
||
solve satisfy; | ||
|
||
output [ show(roster[i,j]) ++ if j==card(DAY) then "\n" else " " endif | ||
| i in NURSE, j in DAY ]; | ||
|
||
/* | ||
Multiline | ||
comment | ||
test | ||
*/ | ||
|
||
predicate atmostone(array[int] of var bool:x) = | ||
forall(i,j in index_set(x) where i < j)( | ||
(not x[i] \/ not x[j])); |