From fcd1dbb98d5ee96b8615577334e585645114f01a Mon Sep 17 00:00:00 2001 From: Conaclos Date: Sun, 20 Jul 2014 17:22:21 +0200 Subject: [PATCH 1/4] Adding Eiffel language mode. - Adding Eiffel highlight rules and Eiffel mode - Use Sudoku grid example of Eiffel Rosetta Code project as Eiffel example --- demo/kitchen-sink/docs/eiffel.e | 246 +++++++++++++++++++++++++ lib/ace/ext/modelist.js | 1 + lib/ace/mode/eiffel.js | 51 +++++ lib/ace/mode/eiffel_highlight_rules.js | 143 ++++++++++++++ 4 files changed, 441 insertions(+) create mode 100644 demo/kitchen-sink/docs/eiffel.e create mode 100644 lib/ace/mode/eiffel.js create mode 100644 lib/ace/mode/eiffel_highlight_rules.js diff --git a/demo/kitchen-sink/docs/eiffel.e b/demo/kitchen-sink/docs/eiffel.e new file mode 100644 index 00000000..4b349566 --- /dev/null +++ b/demo/kitchen-sink/docs/eiffel.e @@ -0,0 +1,246 @@ +note + description: "[ + Sudoku grid and simple resolution facilities. + ]" + author: "Victorien ELVINGER" + date: "22 August 2013" + revision: "3" + libraries: "Relies on ARRAY2 from EiffelBase" + +class + SUDOKU_GRID + +inherit + + ANY + redefine + default_create, + out + end + +create + default_create + +feature {NONE} -- Creation + + default_create + -- Create an empty grid. + do + create grid.make_filled (Default_value, 9, 9) + ensure then + unsolved: not solved + end + +feature -- Access + + item alias "[]" (a_row, a_column: INTEGER): INTEGER assign put + -- Value at coordinates (`a_row', `a_column'). + require + valid_row (a_row) + valid_column (a_column) + do + Result := grid [a_row, a_column] + end + + out: STRING + -- Printable representation. + do + Result := "" + across column_range as column_ic loop + across row_range as row_ic loop + Result := Result + grid [row_ic.item, column_ic.item].out + " " + end + Result := Result + "%N" + end + end + + column_range: INTEGER_INTERVAL + -- Column interval. + do + Result := 1 |..| grid.width + end + + row_range: INTEGER_INTERVAL + -- Row interval. + do + Result := 1 |..| grid.height + end + + subgrid_column_range (a_column: INTEGER): INTEGER_INTERVAL + -- Colum interval of the subgrids including `a_column'. + require + valid_column (a_column) + local + l_column: like a_column + do + l_column := ((a_column - 1) // 3)*3 + 1 + Result := l_column |..| (l_column + 2) + ensure + lower_bound: (<<1, 4, 7>>).has (Result.lower) + upper_bound: (<<3, 6, 9>>).has (Result.upper) + end + + subgrid_row_range (a_row: INTEGER): INTEGER_INTERVAL + -- Row interval of the subgrids including `a_row'. + require + valid_row (a_row) + local + l_row: like a_row + do + l_row := ((a_row - 1) // 3) * 3 + 1 + Result := l_row |..| (l_row + 2) + ensure + lower_bound: (<<1, 4, 7>>).has (Result.lower) + upper_bound: (<<3, 6, 9>>).has (Result.upper) + end + +feature -- Status report + + solved: BOOLEAN + -- Is completed? + + valid_column (a_column: INTEGER): BOOLEAN + -- Is `a_column' a valid coordinate? + do + Result := 1 <= a_column and a_column <= grid.width + end + + valid_row (a_row: INTEGER): BOOLEAN + -- Is `a_row' a valid coordinate? + do + Result := 1 <= a_row and a_row <= grid.height + end + + valid_value (a_value: INTEGER): BOOLEAN + -- Is `a_value' a valid item? + do + Result := 1 <= a_value and a_value <= 9 + end + + valid (a_value: INTEGER; a_row, a_column: INTEGER): BOOLEAN + -- Can `a_value' be inserted at coordinates (`a_row', `a_column')? + require + valid_value (a_value) + valid_row (a_row) + valid_column (a_column) + do + Result := not (subgrid_has (a_value, a_row, a_column) or row_has (a_value, a_row) or column_has (a_value, a_column)) + end + + subgrid_has (a_value: INTEGER; a_row, a_column: INTEGER): BOOLEAN + -- Is there `a_value' in the subgrid containing coordinates (`a_row', `a_column')? + require + valid_row (a_row) + valid_column (a_column) + do + across + subgrid_row_range (a_row) as row_ic + until + Result + loop + across + subgrid_column_range (a_column) as column_ic + until + Result + loop + Result := grid [row_ic.item, column_ic.item] = a_value + end + end + end + + row_has (a_value: INTEGER; a_row: INTEGER): BOOLEAN + -- Exist there an item `a_value' at coordinates (`a_row', ?)? + require + valid_row (a_row) + do + Result := across column_range as ic some grid [a_row, ic.item] = a_value end + end + + column_has (a_value: INTEGER; a_column: INTEGER): BOOLEAN + -- Exist there an item `a_value' at coordinates (?, `a_column')? + require + valid_column (a_column) + do + Result := across row_range as ic some grid [ic.item, a_column] = a_value end + end + +feature -- Extension + + put (a_value: INTEGER; a_row, a_column: INTEGER) + -- Assign item `a_value' at coordinates (`a_row', `a_column'). + require + valid_value (a_value) + valid_row (a_row) + valid_column (a_column) + valid (a_value, a_row, a_column) + do + grid [a_row, a_column] := a_value + ensure + item_inserted: grid [a_row, a_column] = a_value + end + +feature -- Change + + solve + -- Try to solve grid. + do + sub_solve (1, 1) + end + +feature {NONE} -- Implementation + + grid: ARRAY2 [INTEGER] + -- Board. + + Default_value: INTEGER = 0 + -- Empty cell content. + + sub_solve (a_row, a_column: INTEGER) + -- Solve grid from row `a_row' and column `a_column'. + require + valid_row (a_row) + valid_column (a_column) + do + if valid_value (grid [a_row, a_column]) then + solve_after (a_row, a_column) + else + across + 1 |..| 9 as ic + until + solved + loop + if valid (ic.item, a_row, a_column) then + put (ic.item, a_row, a_column) + solve_after (a_row, a_column) + + if not solved then + grid [a_row, a_column] := Default_value + end + end + end + end + end + + solve_after (a_row, a_column: INTEGER) + -- Solve the next cell. + require + valid_row (a_row) + valid_column (a_column) + do + if a_column = grid.width then + if a_row = grid.height then + solved := True + else + sub_solve (a_row + 1, 1) + end + else + sub_solve (a_row, a_column + 1) + end + end + +invariant + valid_numbers: solved implies across grid as ic all valid_value (ic.item) end + nine_columns: grid.width = 9 + nine_rows: grid.height = 9 + +end diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js index 2028386e..53b78f00 100644 --- a/lib/ace/ext/modelist.js +++ b/lib/ace/ext/modelist.js @@ -65,6 +65,7 @@ var supportedModes = { Diff: ["diff|patch"], Dockerfile: ["^Dockerfile"], Dot: ["dot"], + Eiffel: ["e"], Erlang: ["erl|hrl"], EJS: ["ejs"], Forth: ["frt|fs|ldr"], diff --git a/lib/ace/mode/eiffel.js b/lib/ace/mode/eiffel.js new file mode 100644 index 00000000..2ef84ff8 --- /dev/null +++ b/lib/ace/mode/eiffel.js @@ -0,0 +1,51 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2014, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var EiffelHighlightRules = require("./eiffel_highlight_rules").EiffelHighlightRules; +var Range = require("../range").Range; + +var Mode = function() { + this.HighlightRules = EiffelHighlightRules; +}; +oop.inherits(Mode, TextMode); + +(function() { + this.$id = "ace/mode/eiffel"; +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); + diff --git a/lib/ace/mode/eiffel_highlight_rules.js b/lib/ace/mode/eiffel_highlight_rules.js new file mode 100644 index 00000000..f2cc8bd6 --- /dev/null +++ b/lib/ace/mode/eiffel_highlight_rules.js @@ -0,0 +1,143 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2014, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var EiffelHighlightRules = function() { + var keywords = "across|agent|alias|all|attached|as|assign|attribute|check|" + + "class|convert|create|debug|deferred|detachable|do|else|elseif|end|" + + "ensure|expanded|export|external|feature|from|frozen|if|inherit|" + + "inspect|invariant|like|local|loop|not|note|obsolete|old|once|" + + "Precursor|redefine|rename|require|rescue|retry|select|separate|" + + "some|then|undefine|until|variant|when"; + + var operatorKeywords = "and|implies|or|xor"; + + var languageConstants = "Void"; + + var booleanConstants = "True|False"; + + var languageVariables = "Current|Result"; + + var keywordMapper = this.createKeywordMapper({ + "constant.language": languageConstants, + "constant.language.boolean": booleanConstants, + "variable.language": languageVariables, + "keyword.operator": operatorKeywords, + "keyword": keywords + }, "identifier", true); + + this.$rules = { + "start": [{ + token : "comment.line.double-dash", + regex : /--.*$/ + }, { + token : "string.quoted.double", + regex : /"(?:%"|[^%])*?"/ + }, { + token : "string.quoted.other", // "[ ]" aligned verbatim string + regex : /"\[/, + next: "aligned_verbatim_string" + }, { + token : "string.quoted.other", // "{ }" non-aligned verbatim string + regex : /"\{/, + next: "non-aligned_verbatim_string" + }, { + token : "constant.character", + regex : /'(?:%%|%T|%R|%N|%F|%'|[^%])'/ + }, { + token : "constant.numeric", // real + regex : /(?:\d(?:_?\d)*\.|\.\d)(?:\d*[eE][+-]?\d+)?\b/ + }, { + token : "constant.numeric", // integer + regex : /\d(?:_?\d)*\b/ + }, { + token : "constant.numeric", // hex + regex : /0[xX][a-fA-F\d](?:_?[a-fA-F\d])*\b/ + }, { + token : "constant.numeric", // octal + regex : /0[cC][0-7](?:_?[0-7])*\b/ + },{ + token : "constant.numeric", // bin + regex : /0[bB][01](?:_?[01])*\b/ + }, { + token : "keyword.operator", + regex : /\+|\-|\*|\/|\\\\|\/\/|\^|~|\/~|<|>|<=|>=|\/=|=|:=|\|\.\.\||\.\./ + }, { + token : "keyword.operator", // punctuation + regex : /\.|:|,|;\b/ + }, { + token : function (v) { + var result = keywordMapper (v); + if (result === "identifier" && v === v.toUpperCase ()) { + result = "entity.name.type"; + } + return result; + }, + regex : /[a-zA-Z][a-zA-Z\d_]*\b/ + }, { + token : "paren.lparen", + regex : /[\[({]/ + }, { + token : "paren.rparen", + regex : /[\])}]/ + }, { + token : "text", + regex : /\s+/ + } + ], + "aligned_verbatim_string" : [{ + token : "string", // closing multi-line comment + regex : /]"/, + next : "start" + }, { + token : "string", // comment spanning whole line + regex : /[^(?:\]")]+/ + } + ], + "non-aligned_verbatim_string" : [{ + token : "string.quoted.other", // closing multi-line comment + regex : /}"/, + next : "start" + }, { + token : "string.quoted.other", // comment spanning whole line + regex : /[^(?:\}")]+/ + } + ]}; +}; + +oop.inherits(EiffelHighlightRules, TextHighlightRules); + +exports.EiffelHighlightRules = EiffelHighlightRules; +}); From 7e55724c522598378c9d16f8893cf222ad5bf202 Mon Sep 17 00:00:00 2001 From: Conaclos Date: Sun, 20 Jul 2014 19:10:50 +0200 Subject: [PATCH 2/4] Add comment mark in Eiffel mode. --- lib/ace/mode/eiffel.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/mode/eiffel.js b/lib/ace/mode/eiffel.js index 2ef84ff8..f8ba173b 100644 --- a/lib/ace/mode/eiffel.js +++ b/lib/ace/mode/eiffel.js @@ -42,6 +42,7 @@ var Mode = function() { oop.inherits(Mode, TextMode); (function() { + this.lineCommentStart = "--"; this.$id = "ace/mode/eiffel"; }).call(Mode.prototype); From 9284732a28f727b3185cec56e4f0d236b221d1bc Mon Sep 17 00:00:00 2001 From: Conaclos Date: Sun, 20 Jul 2014 19:12:03 +0200 Subject: [PATCH 3/4] Remove eiffel example. Current example is too large. --- demo/kitchen-sink/docs/eiffel.e | 246 -------------------------------- 1 file changed, 246 deletions(-) delete mode 100644 demo/kitchen-sink/docs/eiffel.e diff --git a/demo/kitchen-sink/docs/eiffel.e b/demo/kitchen-sink/docs/eiffel.e deleted file mode 100644 index 4b349566..00000000 --- a/demo/kitchen-sink/docs/eiffel.e +++ /dev/null @@ -1,246 +0,0 @@ -note - description: "[ - Sudoku grid and simple resolution facilities. - ]" - author: "Victorien ELVINGER" - date: "22 August 2013" - revision: "3" - libraries: "Relies on ARRAY2 from EiffelBase" - -class - SUDOKU_GRID - -inherit - - ANY - redefine - default_create, - out - end - -create - default_create - -feature {NONE} -- Creation - - default_create - -- Create an empty grid. - do - create grid.make_filled (Default_value, 9, 9) - ensure then - unsolved: not solved - end - -feature -- Access - - item alias "[]" (a_row, a_column: INTEGER): INTEGER assign put - -- Value at coordinates (`a_row', `a_column'). - require - valid_row (a_row) - valid_column (a_column) - do - Result := grid [a_row, a_column] - end - - out: STRING - -- Printable representation. - do - Result := "" - across column_range as column_ic loop - across row_range as row_ic loop - Result := Result + grid [row_ic.item, column_ic.item].out + " " - end - Result := Result + "%N" - end - end - - column_range: INTEGER_INTERVAL - -- Column interval. - do - Result := 1 |..| grid.width - end - - row_range: INTEGER_INTERVAL - -- Row interval. - do - Result := 1 |..| grid.height - end - - subgrid_column_range (a_column: INTEGER): INTEGER_INTERVAL - -- Colum interval of the subgrids including `a_column'. - require - valid_column (a_column) - local - l_column: like a_column - do - l_column := ((a_column - 1) // 3)*3 + 1 - Result := l_column |..| (l_column + 2) - ensure - lower_bound: (<<1, 4, 7>>).has (Result.lower) - upper_bound: (<<3, 6, 9>>).has (Result.upper) - end - - subgrid_row_range (a_row: INTEGER): INTEGER_INTERVAL - -- Row interval of the subgrids including `a_row'. - require - valid_row (a_row) - local - l_row: like a_row - do - l_row := ((a_row - 1) // 3) * 3 + 1 - Result := l_row |..| (l_row + 2) - ensure - lower_bound: (<<1, 4, 7>>).has (Result.lower) - upper_bound: (<<3, 6, 9>>).has (Result.upper) - end - -feature -- Status report - - solved: BOOLEAN - -- Is completed? - - valid_column (a_column: INTEGER): BOOLEAN - -- Is `a_column' a valid coordinate? - do - Result := 1 <= a_column and a_column <= grid.width - end - - valid_row (a_row: INTEGER): BOOLEAN - -- Is `a_row' a valid coordinate? - do - Result := 1 <= a_row and a_row <= grid.height - end - - valid_value (a_value: INTEGER): BOOLEAN - -- Is `a_value' a valid item? - do - Result := 1 <= a_value and a_value <= 9 - end - - valid (a_value: INTEGER; a_row, a_column: INTEGER): BOOLEAN - -- Can `a_value' be inserted at coordinates (`a_row', `a_column')? - require - valid_value (a_value) - valid_row (a_row) - valid_column (a_column) - do - Result := not (subgrid_has (a_value, a_row, a_column) or row_has (a_value, a_row) or column_has (a_value, a_column)) - end - - subgrid_has (a_value: INTEGER; a_row, a_column: INTEGER): BOOLEAN - -- Is there `a_value' in the subgrid containing coordinates (`a_row', `a_column')? - require - valid_row (a_row) - valid_column (a_column) - do - across - subgrid_row_range (a_row) as row_ic - until - Result - loop - across - subgrid_column_range (a_column) as column_ic - until - Result - loop - Result := grid [row_ic.item, column_ic.item] = a_value - end - end - end - - row_has (a_value: INTEGER; a_row: INTEGER): BOOLEAN - -- Exist there an item `a_value' at coordinates (`a_row', ?)? - require - valid_row (a_row) - do - Result := across column_range as ic some grid [a_row, ic.item] = a_value end - end - - column_has (a_value: INTEGER; a_column: INTEGER): BOOLEAN - -- Exist there an item `a_value' at coordinates (?, `a_column')? - require - valid_column (a_column) - do - Result := across row_range as ic some grid [ic.item, a_column] = a_value end - end - -feature -- Extension - - put (a_value: INTEGER; a_row, a_column: INTEGER) - -- Assign item `a_value' at coordinates (`a_row', `a_column'). - require - valid_value (a_value) - valid_row (a_row) - valid_column (a_column) - valid (a_value, a_row, a_column) - do - grid [a_row, a_column] := a_value - ensure - item_inserted: grid [a_row, a_column] = a_value - end - -feature -- Change - - solve - -- Try to solve grid. - do - sub_solve (1, 1) - end - -feature {NONE} -- Implementation - - grid: ARRAY2 [INTEGER] - -- Board. - - Default_value: INTEGER = 0 - -- Empty cell content. - - sub_solve (a_row, a_column: INTEGER) - -- Solve grid from row `a_row' and column `a_column'. - require - valid_row (a_row) - valid_column (a_column) - do - if valid_value (grid [a_row, a_column]) then - solve_after (a_row, a_column) - else - across - 1 |..| 9 as ic - until - solved - loop - if valid (ic.item, a_row, a_column) then - put (ic.item, a_row, a_column) - solve_after (a_row, a_column) - - if not solved then - grid [a_row, a_column] := Default_value - end - end - end - end - end - - solve_after (a_row, a_column: INTEGER) - -- Solve the next cell. - require - valid_row (a_row) - valid_column (a_column) - do - if a_column = grid.width then - if a_row = grid.height then - solved := True - else - sub_solve (a_row + 1, 1) - end - else - sub_solve (a_row, a_column + 1) - end - end - -invariant - valid_numbers: solved implies across grid as ic all valid_value (ic.item) end - nine_columns: grid.width = 9 - nine_rows: grid.height = 9 - -end From b651a424f101f1f448c085ac2828757d7b6bb9ab Mon Sep 17 00:00:00 2001 From: Conaclos Date: Sun, 20 Jul 2014 19:12:34 +0200 Subject: [PATCH 4/4] Adding the new Eiffel example. --- demo/kitchen-sink/docs/eiffel.e | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 demo/kitchen-sink/docs/eiffel.e diff --git a/demo/kitchen-sink/docs/eiffel.e b/demo/kitchen-sink/docs/eiffel.e new file mode 100644 index 00000000..943cdb35 --- /dev/null +++ b/demo/kitchen-sink/docs/eiffel.e @@ -0,0 +1,30 @@ +note + description: "Represents a person." + +class + PERSON + +create + make, make_unknown + +feature {NONE} -- Creation + + make (a_name: like name) + -- Create a person with `a_name' as `name'. + do + name := a_name + ensure + name = a_name + end + + make_unknown + do ensure + name = Void + end + +feature -- Access + + name: detachable STRING + -- Full name or Void if unknown. + +end \ No newline at end of file