Skip to content

Commit

Permalink
enh(gcode): rewrote language for moden gcode support (#4040)
Browse files Browse the repository at this point in the history
  • Loading branch information
barthy-koeln authored Oct 31, 2024
1 parent 48104f9 commit 7893353
Show file tree
Hide file tree
Showing 5 changed files with 353 additions and 72 deletions.
3 changes: 2 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Core Grammars:
- fix(c) - Fixed hex numbers with decimals [Dxuian]
- fix(typescript) - Fixedoptional property not highlighted correctly [Dxuian]
- fix(ruby) - fix `|=` operator false positives (as block arguments) [Aboobacker MK]
- enh(gcode) rewrote language for modern gcode support [Barthélémy Bonhomme][]
- fix(sql) - Fixed sql primary key and foreign key spacing issue [Dxuian]
- fix(cpp) added flat_set and flat_map as a part of cpp 23 version [Lavan]
- fix(yaml) - Fixed special chars in yaml [Dxuian]
Expand Down Expand Up @@ -70,6 +71,7 @@ CONTRIBUTORS
[Sainan]: https://github.com/Sainan
[Osmocom]: https://github.com/osmocom
[Álvaro Mondéjar]: https://github.com/mondeja
[Barthélémy Bonhomme]: https://github.com/barthy-koeln
[Lavan]: https://github.com/jvlavan
[Somya]: https://github.com/somya-05
[guuido]: https://github.com/guuido
Expand Down Expand Up @@ -184,7 +186,6 @@ Themes:
[Chiel van de Steeg]: https://github.com/cvdsteeg



## Version 11.9.0

CAVEATS / POTENTIALLY BREAKING CHANGES
Expand Down
190 changes: 149 additions & 41 deletions src/languages/gcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,58 +7,170 @@
*/

export default function(hljs) {
const GCODE_IDENT_RE = '[A-Z_][A-Z0-9_.]*';
const GCODE_CLOSE_RE = '%';
const regex = hljs.regex;
const GCODE_KEYWORDS = {
$pattern: GCODE_IDENT_RE,
keyword: 'IF DO WHILE ENDWHILE CALL ENDIF SUB ENDSUB GOTO REPEAT ENDREPEAT '
+ 'EQ LT GT NE GE LE OR XOR'
};
const GCODE_START = {
className: 'meta',
begin: '([O])([0-9]+)'
$pattern: /[A-Z]+|%/,
keyword: [
// conditions
'THEN',
'ELSE',
'ENDIF',
'IF',

// controls
'GOTO',
'DO',
'WHILE',
'WH',
'END',
'CALL',

// scoping
'SUB',
'ENDSUB',

// comparisons
'EQ',
'NE',
'LT',
'GT',
'LE',
'GE',
'AND',
'OR',
'XOR',

// start/end of program
'%'
],
built_in: [
'ATAN',
'ABS',
'ACOS',
'ASIN',
'COS',
'EXP',
'FIX',
'FUP',
'ROUND',
'LN',
'SIN',
'SQRT',
'TAN',
'EXISTS'
]
};
const NUMBER = hljs.inherit(hljs.C_NUMBER_MODE, { begin: '([-+]?((\\.\\d+)|(\\d+)(\\.\\d*)?))|' + hljs.C_NUMBER_RE });


// TODO: post v12 lets use look-behind, until then \b and a callback filter will be used
// const LETTER_BOUNDARY_RE = /(?<![A-Z])/;
const LETTER_BOUNDARY_RE = /\b/;

function LETTER_BOUNDARY_CALLBACK(matchdata, response) {
if (matchdata.index === 0) {
return;
}

const charBeforeMatch = matchdata.input[matchdata.index - 1];
if (charBeforeMatch >= '0' && charBeforeMatch <= '9') {
return;
}

if (charBeforeMatch === '_') {
return;
}

response.ignoreMatch();
}

const NUMBER_RE = /[+-]?((\.\d+)|(\d+)(\.\d*)?)/;

const GENERAL_MISC_FUNCTION_RE = /[GM]\s*\d+(\.\d+)?/;
const TOOLS_RE = /T\s*\d+/;
const SUBROUTINE_RE = /O\s*\d+/;
const SUBROUTINE_NAMED_RE = /O<.+>/;
const AXES_RE = /[ABCUVWXYZ]\s*/;
const PARAMETERS_RE = /[FHIJKPQRS]\s*/;

const GCODE_CODE = [
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
// comments
hljs.COMMENT(/\(/, /\)/),
NUMBER,
hljs.inherit(hljs.APOS_STRING_MODE, { illegal: null }),
hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }),
hljs.COMMENT(/;/, /$/),
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE,
hljs.C_NUMBER_MODE,

// gcodes
{
className: 'name',
begin: '([G])([0-9]+\\.?[0-9]?)'
scope: 'title.function',
variants: [
// G General functions: G0, G5.1, G5.2, …
// M Misc functions: M0, M55.6, M199, …
{ match: regex.concat(LETTER_BOUNDARY_RE, GENERAL_MISC_FUNCTION_RE) },
{
begin: GENERAL_MISC_FUNCTION_RE,
'on:begin': LETTER_BOUNDARY_CALLBACK
},
// T Tools
{ match: regex.concat(LETTER_BOUNDARY_RE, TOOLS_RE), },
{
begin: TOOLS_RE,
'on:begin': LETTER_BOUNDARY_CALLBACK
}
]
},

{
className: 'name',
begin: '([M])([0-9]+\\.?[0-9]?)'
scope: 'symbol',
variants: [
// O Subroutine ID: O100, O110, …
{ match: regex.concat(LETTER_BOUNDARY_RE, SUBROUTINE_RE) },
{
begin: SUBROUTINE_RE,
'on:begin': LETTER_BOUNDARY_CALLBACK
},
// O Subroutine name: O<some>, …
{ match: regex.concat(LETTER_BOUNDARY_RE, SUBROUTINE_NAMED_RE) },
{
begin: SUBROUTINE_NAMED_RE,
'on:begin': LETTER_BOUNDARY_CALLBACK
},
// Checksum at end of line: *71, *199, …
{ match: /\*\s*\d+\s*$/ }
]
},

{
className: 'attr',
begin: '(VC|VS|#)',
end: '(\\d+)'
scope: 'operator', // N Line number: N1, N2, N1020, …
match: /^N\s*\d+/
},

{
className: 'attr',
begin: '(VZOFX|VZOFY|VZOFZ)'
scope: 'variable',
match: /-?#\s*\d+/
},

{
className: 'built_in',
begin: '(ATAN|ABS|ACOS|ASIN|SIN|COS|EXP|FIX|FUP|ROUND|LN|TAN)(\\[)',
contains: [ NUMBER ],
end: '\\]'
scope: 'property', // Physical axes,
variants: [
{ match: regex.concat(LETTER_BOUNDARY_RE, AXES_RE, NUMBER_RE) },
{
begin: regex.concat(AXES_RE, NUMBER_RE),
'on:begin': LETTER_BOUNDARY_CALLBACK
},
]
},

{
className: 'symbol',
scope: 'params', // Different types of parameters
variants: [
{ match: regex.concat(LETTER_BOUNDARY_RE, PARAMETERS_RE, NUMBER_RE) },
{
begin: 'N',
end: '\\d+',
illegal: '\\W'
}
begin: regex.concat(PARAMETERS_RE, NUMBER_RE),
'on:begin': LETTER_BOUNDARY_CALLBACK
},
]
}
},
];

return {
Expand All @@ -67,13 +179,9 @@ export default function(hljs) {
// Some implementations (CNC controls) of G-code are interoperable with uppercase and lowercase letters seamlessly.
// However, most prefer all uppercase and uppercase is customary.
case_insensitive: true,
// TODO: post v12 with the use of look-behind this can be enabled
disableAutodetect: true,
keywords: GCODE_KEYWORDS,
contains: [
{
className: 'meta',
begin: GCODE_CLOSE_RE
},
GCODE_START
].concat(GCODE_CODE)
contains: GCODE_CODE
};
}
60 changes: 30 additions & 30 deletions test/markup/gcode/default.expect.txt
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
<span class="hljs-meta">O003</span> <span class="hljs-comment">(DIAMOND SQUARE)</span>
<span class="hljs-symbol">N2</span> <span class="hljs-name">G54</span> <span class="hljs-name">G90</span> <span class="hljs-name">G49</span> <span class="hljs-name">G80</span>
<span class="hljs-symbol">N3</span> <span class="hljs-name">M6</span> T<span class="hljs-number">1</span> <span class="hljs-comment">(1.ENDMILL)</span>
<span class="hljs-symbol">N4</span> <span class="hljs-name">M3</span> S<span class="hljs-number">1800</span>
<span class="hljs-symbol">N5</span> <span class="hljs-name">G0</span> X<span class="hljs-number">-.6</span> Y<span class="hljs-number">2.050</span>
<span class="hljs-symbol">N6</span> <span class="hljs-name">G43</span> H<span class="hljs-number">1</span> Z<span class="hljs-number">.1</span>
<span class="hljs-symbol">N7</span> <span class="hljs-name">G1</span> Z<span class="hljs-number">-.3</span> F<span class="hljs-number">50.</span>
<span class="hljs-symbol">N8</span> <span class="hljs-name">G41</span> D<span class="hljs-number">1</span> Y<span class="hljs-number">1.45</span>
<span class="hljs-symbol">N9</span> <span class="hljs-name">G1</span> X<span class="hljs-number">0</span> F<span class="hljs-number">20.</span>
<span class="hljs-symbol">N10</span> <span class="hljs-name">G2</span> J<span class="hljs-number">-1.45</span>
<span class="hljs-symbol">O003</span> <span class="hljs-comment">(DIAMOND SQUARE)</span>
<span class="hljs-operator">N2</span> <span class="hljs-title function_">G54</span> <span class="hljs-title function_">G90</span> <span class="hljs-title function_">G49</span> <span class="hljs-title function_">G80</span>
<span class="hljs-operator">N3</span> <span class="hljs-title function_">M6</span> <span class="hljs-title function_">T1</span> <span class="hljs-comment">(1.ENDMILL)</span>
<span class="hljs-operator">N4</span> <span class="hljs-title function_">M3</span> <span class="hljs-params">S1800</span>
<span class="hljs-operator">N5</span> <span class="hljs-title function_">G0</span> <span class="hljs-property">X-.6</span> <span class="hljs-property">Y2.050</span>
<span class="hljs-operator">N6</span> <span class="hljs-title function_">G43</span> <span class="hljs-params">H1</span> <span class="hljs-property">Z.1</span>
<span class="hljs-operator">N7</span> <span class="hljs-title function_">G1</span> <span class="hljs-property">Z-.3</span> <span class="hljs-params">F50.</span>
<span class="hljs-operator">N8</span> <span class="hljs-title function_">G41</span> D1 <span class="hljs-property">Y1.45</span>
<span class="hljs-operator">N9</span> <span class="hljs-title function_">G1</span> <span class="hljs-property">X0</span> <span class="hljs-params">F20.</span>
<span class="hljs-operator">N10</span> <span class="hljs-title function_">G2</span> <span class="hljs-params">J-1.45</span>
<span class="hljs-comment">(CUTTER COMP CANCEL)</span>
<span class="hljs-symbol">N11</span> <span class="hljs-name">G1</span> Z<span class="hljs-number">-.2</span> F<span class="hljs-number">50.</span>
<span class="hljs-symbol">N12</span> Y<span class="hljs-number">-.990</span>
<span class="hljs-symbol">N13</span> <span class="hljs-name">G40</span>
<span class="hljs-symbol">N14</span> <span class="hljs-name">G0</span> X<span class="hljs-number">-.6</span> Y<span class="hljs-number">1.590</span>
<span class="hljs-symbol">N15</span> <span class="hljs-name">G0</span> Z<span class="hljs-number">.1</span>
<span class="hljs-symbol">N16</span> <span class="hljs-name">M5</span> <span class="hljs-name">G49</span> <span class="hljs-name">G28</span> <span class="hljs-name">G91</span> Z<span class="hljs-number">0</span>
<span class="hljs-symbol">N17</span> <span class="hljs-keyword">CALL</span> <span class="hljs-meta">O9456</span>
<span class="hljs-symbol">N18</span> <span class="hljs-attr">#500</span>=<span class="hljs-number">0.004</span>
<span class="hljs-symbol">N19</span> <span class="hljs-attr">#503</span>=[<span class="hljs-attr">#500</span>+<span class="hljs-attr">#501</span>]
<span class="hljs-symbol">N20</span> <span class="hljs-attr">VC45</span>=<span class="hljs-number">0.0006</span>
<span class="hljs-attr">VS4</span>=<span class="hljs-number">0.0007</span>
<span class="hljs-symbol">N21</span> <span class="hljs-name">G90</span> <span class="hljs-name">G10</span> L<span class="hljs-number">20</span> P<span class="hljs-number">3</span> X<span class="hljs-number">5.</span>Y<span class="hljs-number">4.</span> Z<span class="hljs-number">6.567</span>
<span class="hljs-symbol">N22</span> <span class="hljs-name">G0</span> X<span class="hljs-number">5000</span>
<span class="hljs-symbol">N23</span> <span class="hljs-keyword">IF</span> [<span class="hljs-attr">#1</span> <span class="hljs-keyword">LT</span> <span class="hljs-number">0.370</span>] <span class="hljs-keyword">GOTO</span> <span class="hljs-number">49</span>
<span class="hljs-symbol">N24</span> X<span class="hljs-number">-0.678</span> Y<span class="hljs-number">+.990</span>
<span class="hljs-symbol">N25</span> <span class="hljs-name">G84.3</span> X<span class="hljs-number">-0.1</span>
<span class="hljs-symbol">N26</span> <span class="hljs-attr">#4</span>=<span class="hljs-attr">#5</span>*<span class="hljs-built_in">COS[<span class="hljs-number">45</span>]</span>
<span class="hljs-symbol">N27</span> <span class="hljs-attr">#4</span>=<span class="hljs-attr">#5</span>*<span class="hljs-built_in">SIN[<span class="hljs-number">45</span>]</span>
<span class="hljs-symbol">N28</span> <span class="hljs-attr">VZOFZ</span>=<span class="hljs-number">652.9658</span>
<span class="hljs-meta">%</span>
<span class="hljs-operator">N11</span> <span class="hljs-title function_">G1</span> <span class="hljs-property">Z-.2</span> <span class="hljs-params">F50.</span>
<span class="hljs-operator">N12</span> <span class="hljs-property">Y-.990</span>
<span class="hljs-operator">N13</span> <span class="hljs-title function_">G40</span>
<span class="hljs-operator">N14</span> <span class="hljs-title function_">G0</span> <span class="hljs-property">X-.6</span> <span class="hljs-property">Y1.590</span>
<span class="hljs-operator">N15</span> <span class="hljs-title function_">G0</span> <span class="hljs-property">Z.1</span>
<span class="hljs-operator">N16</span> <span class="hljs-title function_">M5</span> <span class="hljs-title function_">G49</span> <span class="hljs-title function_">G28</span> <span class="hljs-title function_">G91</span> <span class="hljs-property">Z0</span>
<span class="hljs-operator">N17</span> <span class="hljs-keyword">CALL</span> <span class="hljs-symbol">O9456</span>
<span class="hljs-operator">N18</span> <span class="hljs-variable">#500</span>=<span class="hljs-number">0.004</span>
<span class="hljs-operator">N19</span> <span class="hljs-variable">#503</span>=[<span class="hljs-variable">#500</span>+<span class="hljs-variable">#501</span>]
<span class="hljs-operator">N20</span> VC45=<span class="hljs-number">0.0006</span>
VS4=<span class="hljs-number">0.0007</span>
<span class="hljs-operator">N21</span> <span class="hljs-title function_">G90</span> <span class="hljs-title function_">G10</span> L20 <span class="hljs-params">P3</span> <span class="hljs-property">X5.</span><span class="hljs-property">Y4.</span> <span class="hljs-property">Z6.567</span>
<span class="hljs-operator">N22</span> <span class="hljs-title function_">G0</span> <span class="hljs-property">X5000</span>
<span class="hljs-operator">N23</span> <span class="hljs-keyword">IF</span> [<span class="hljs-variable">#1</span> <span class="hljs-keyword">LT</span> <span class="hljs-number">0.370</span>] <span class="hljs-keyword">GOTO</span> <span class="hljs-number">49</span>
<span class="hljs-operator">N24</span> <span class="hljs-property">X-0.678</span> <span class="hljs-property">Y+.990</span>
<span class="hljs-operator">N25</span> <span class="hljs-title function_">G84.3</span> <span class="hljs-property">X-0.1</span>
<span class="hljs-operator">N26</span> <span class="hljs-variable">#4</span>=<span class="hljs-variable">#5</span>*<span class="hljs-built_in">COS</span>[<span class="hljs-number">45</span>]
<span class="hljs-operator">N27</span> <span class="hljs-variable">#4</span>=<span class="hljs-variable">#5</span>*<span class="hljs-built_in">SIN</span>[<span class="hljs-number">45</span>]
<span class="hljs-operator">N28</span> VZOFZ=<span class="hljs-number">652.9658</span>
<span class="hljs-keyword">%</span>
Loading

0 comments on commit 7893353

Please sign in to comment.