Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enh(gcode): rewrote language for moden gcode support #4040

Merged
merged 6 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
joshgoebel marked this conversation as resolved.
Show resolved Hide resolved
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)'
joshgoebel marked this conversation as resolved.
Show resolved Hide resolved
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