Skip to content

Commit 7893353

Browse files
authored
enh(gcode): rewrote language for moden gcode support (#4040)
1 parent 48104f9 commit 7893353

File tree

5 files changed

+353
-72
lines changed

5 files changed

+353
-72
lines changed

CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Core Grammars:
2828
- fix(c) - Fixed hex numbers with decimals [Dxuian]
2929
- fix(typescript) - Fixedoptional property not highlighted correctly [Dxuian]
3030
- fix(ruby) - fix `|=` operator false positives (as block arguments) [Aboobacker MK]
31+
- enh(gcode) rewrote language for modern gcode support [Barthélémy Bonhomme][]
3132
- fix(sql) - Fixed sql primary key and foreign key spacing issue [Dxuian]
3233
- fix(cpp) added flat_set and flat_map as a part of cpp 23 version [Lavan]
3334
- fix(yaml) - Fixed special chars in yaml [Dxuian]
@@ -70,6 +71,7 @@ CONTRIBUTORS
7071
[Sainan]: https://github.com/Sainan
7172
[Osmocom]: https://github.com/osmocom
7273
[Álvaro Mondéjar]: https://github.com/mondeja
74+
[Barthélémy Bonhomme]: https://github.com/barthy-koeln
7375
[Lavan]: https://github.com/jvlavan
7476
[Somya]: https://github.com/somya-05
7577
[guuido]: https://github.com/guuido
@@ -184,7 +186,6 @@ Themes:
184186
[Chiel van de Steeg]: https://github.com/cvdsteeg
185187

186188

187-
188189
## Version 11.9.0
189190

190191
CAVEATS / POTENTIALLY BREAKING CHANGES

src/languages/gcode.js

Lines changed: 149 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,58 +7,170 @@
77
*/
88

99
export default function(hljs) {
10-
const GCODE_IDENT_RE = '[A-Z_][A-Z0-9_.]*';
11-
const GCODE_CLOSE_RE = '%';
10+
const regex = hljs.regex;
1211
const GCODE_KEYWORDS = {
13-
$pattern: GCODE_IDENT_RE,
14-
keyword: 'IF DO WHILE ENDWHILE CALL ENDIF SUB ENDSUB GOTO REPEAT ENDREPEAT '
15-
+ 'EQ LT GT NE GE LE OR XOR'
16-
};
17-
const GCODE_START = {
18-
className: 'meta',
19-
begin: '([O])([0-9]+)'
12+
$pattern: /[A-Z]+|%/,
13+
keyword: [
14+
// conditions
15+
'THEN',
16+
'ELSE',
17+
'ENDIF',
18+
'IF',
19+
20+
// controls
21+
'GOTO',
22+
'DO',
23+
'WHILE',
24+
'WH',
25+
'END',
26+
'CALL',
27+
28+
// scoping
29+
'SUB',
30+
'ENDSUB',
31+
32+
// comparisons
33+
'EQ',
34+
'NE',
35+
'LT',
36+
'GT',
37+
'LE',
38+
'GE',
39+
'AND',
40+
'OR',
41+
'XOR',
42+
43+
// start/end of program
44+
'%'
45+
],
46+
built_in: [
47+
'ATAN',
48+
'ABS',
49+
'ACOS',
50+
'ASIN',
51+
'COS',
52+
'EXP',
53+
'FIX',
54+
'FUP',
55+
'ROUND',
56+
'LN',
57+
'SIN',
58+
'SQRT',
59+
'TAN',
60+
'EXISTS'
61+
]
2062
};
21-
const NUMBER = hljs.inherit(hljs.C_NUMBER_MODE, { begin: '([-+]?((\\.\\d+)|(\\d+)(\\.\\d*)?))|' + hljs.C_NUMBER_RE });
63+
64+
65+
// TODO: post v12 lets use look-behind, until then \b and a callback filter will be used
66+
// const LETTER_BOUNDARY_RE = /(?<![A-Z])/;
67+
const LETTER_BOUNDARY_RE = /\b/;
68+
69+
function LETTER_BOUNDARY_CALLBACK(matchdata, response) {
70+
if (matchdata.index === 0) {
71+
return;
72+
}
73+
74+
const charBeforeMatch = matchdata.input[matchdata.index - 1];
75+
if (charBeforeMatch >= '0' && charBeforeMatch <= '9') {
76+
return;
77+
}
78+
79+
if (charBeforeMatch === '_') {
80+
return;
81+
}
82+
83+
response.ignoreMatch();
84+
}
85+
86+
const NUMBER_RE = /[+-]?((\.\d+)|(\d+)(\.\d*)?)/;
87+
88+
const GENERAL_MISC_FUNCTION_RE = /[GM]\s*\d+(\.\d+)?/;
89+
const TOOLS_RE = /T\s*\d+/;
90+
const SUBROUTINE_RE = /O\s*\d+/;
91+
const SUBROUTINE_NAMED_RE = /O<.+>/;
92+
const AXES_RE = /[ABCUVWXYZ]\s*/;
93+
const PARAMETERS_RE = /[FHIJKPQRS]\s*/;
94+
2295
const GCODE_CODE = [
23-
hljs.C_LINE_COMMENT_MODE,
24-
hljs.C_BLOCK_COMMENT_MODE,
96+
// comments
2597
hljs.COMMENT(/\(/, /\)/),
26-
NUMBER,
27-
hljs.inherit(hljs.APOS_STRING_MODE, { illegal: null }),
28-
hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }),
98+
hljs.COMMENT(/;/, /$/),
99+
hljs.APOS_STRING_MODE,
100+
hljs.QUOTE_STRING_MODE,
101+
hljs.C_NUMBER_MODE,
102+
103+
// gcodes
29104
{
30-
className: 'name',
31-
begin: '([G])([0-9]+\\.?[0-9]?)'
105+
scope: 'title.function',
106+
variants: [
107+
// G General functions: G0, G5.1, G5.2, …
108+
// M Misc functions: M0, M55.6, M199, …
109+
{ match: regex.concat(LETTER_BOUNDARY_RE, GENERAL_MISC_FUNCTION_RE) },
110+
{
111+
begin: GENERAL_MISC_FUNCTION_RE,
112+
'on:begin': LETTER_BOUNDARY_CALLBACK
113+
},
114+
// T Tools
115+
{ match: regex.concat(LETTER_BOUNDARY_RE, TOOLS_RE), },
116+
{
117+
begin: TOOLS_RE,
118+
'on:begin': LETTER_BOUNDARY_CALLBACK
119+
}
120+
]
32121
},
122+
33123
{
34-
className: 'name',
35-
begin: '([M])([0-9]+\\.?[0-9]?)'
124+
scope: 'symbol',
125+
variants: [
126+
// O Subroutine ID: O100, O110, …
127+
{ match: regex.concat(LETTER_BOUNDARY_RE, SUBROUTINE_RE) },
128+
{
129+
begin: SUBROUTINE_RE,
130+
'on:begin': LETTER_BOUNDARY_CALLBACK
131+
},
132+
// O Subroutine name: O<some>, …
133+
{ match: regex.concat(LETTER_BOUNDARY_RE, SUBROUTINE_NAMED_RE) },
134+
{
135+
begin: SUBROUTINE_NAMED_RE,
136+
'on:begin': LETTER_BOUNDARY_CALLBACK
137+
},
138+
// Checksum at end of line: *71, *199, …
139+
{ match: /\*\s*\d+\s*$/ }
140+
]
36141
},
142+
37143
{
38-
className: 'attr',
39-
begin: '(VC|VS|#)',
40-
end: '(\\d+)'
144+
scope: 'operator', // N Line number: N1, N2, N1020, …
145+
match: /^N\s*\d+/
41146
},
147+
42148
{
43-
className: 'attr',
44-
begin: '(VZOFX|VZOFY|VZOFZ)'
149+
scope: 'variable',
150+
match: /-?#\s*\d+/
45151
},
152+
46153
{
47-
className: 'built_in',
48-
begin: '(ATAN|ABS|ACOS|ASIN|SIN|COS|EXP|FIX|FUP|ROUND|LN|TAN)(\\[)',
49-
contains: [ NUMBER ],
50-
end: '\\]'
154+
scope: 'property', // Physical axes,
155+
variants: [
156+
{ match: regex.concat(LETTER_BOUNDARY_RE, AXES_RE, NUMBER_RE) },
157+
{
158+
begin: regex.concat(AXES_RE, NUMBER_RE),
159+
'on:begin': LETTER_BOUNDARY_CALLBACK
160+
},
161+
]
51162
},
163+
52164
{
53-
className: 'symbol',
165+
scope: 'params', // Different types of parameters
54166
variants: [
167+
{ match: regex.concat(LETTER_BOUNDARY_RE, PARAMETERS_RE, NUMBER_RE) },
55168
{
56-
begin: 'N',
57-
end: '\\d+',
58-
illegal: '\\W'
59-
}
169+
begin: regex.concat(PARAMETERS_RE, NUMBER_RE),
170+
'on:begin': LETTER_BOUNDARY_CALLBACK
171+
},
60172
]
61-
}
173+
},
62174
];
63175

64176
return {
@@ -67,13 +179,9 @@ export default function(hljs) {
67179
// Some implementations (CNC controls) of G-code are interoperable with uppercase and lowercase letters seamlessly.
68180
// However, most prefer all uppercase and uppercase is customary.
69181
case_insensitive: true,
182+
// TODO: post v12 with the use of look-behind this can be enabled
183+
disableAutodetect: true,
70184
keywords: GCODE_KEYWORDS,
71-
contains: [
72-
{
73-
className: 'meta',
74-
begin: GCODE_CLOSE_RE
75-
},
76-
GCODE_START
77-
].concat(GCODE_CODE)
185+
contains: GCODE_CODE
78186
};
79187
}

test/markup/gcode/default.expect.txt

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
1-
<span class="hljs-meta">O003</span> <span class="hljs-comment">(DIAMOND SQUARE)</span>
2-
<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>
3-
<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>
4-
<span class="hljs-symbol">N4</span> <span class="hljs-name">M3</span> S<span class="hljs-number">1800</span>
5-
<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>
6-
<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>
7-
<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>
8-
<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>
9-
<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>
10-
<span class="hljs-symbol">N10</span> <span class="hljs-name">G2</span> J<span class="hljs-number">-1.45</span>
1+
<span class="hljs-symbol">O003</span> <span class="hljs-comment">(DIAMOND SQUARE)</span>
2+
<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>
3+
<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>
4+
<span class="hljs-operator">N4</span> <span class="hljs-title function_">M3</span> <span class="hljs-params">S1800</span>
5+
<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>
6+
<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>
7+
<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>
8+
<span class="hljs-operator">N8</span> <span class="hljs-title function_">G41</span> D1 <span class="hljs-property">Y1.45</span>
9+
<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>
10+
<span class="hljs-operator">N10</span> <span class="hljs-title function_">G2</span> <span class="hljs-params">J-1.45</span>
1111
<span class="hljs-comment">(CUTTER COMP CANCEL)</span>
12-
<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>
13-
<span class="hljs-symbol">N12</span> Y<span class="hljs-number">-.990</span>
14-
<span class="hljs-symbol">N13</span> <span class="hljs-name">G40</span>
15-
<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>
16-
<span class="hljs-symbol">N15</span> <span class="hljs-name">G0</span> Z<span class="hljs-number">.1</span>
17-
<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>
18-
<span class="hljs-symbol">N17</span> <span class="hljs-keyword">CALL</span> <span class="hljs-meta">O9456</span>
19-
<span class="hljs-symbol">N18</span> <span class="hljs-attr">#500</span>=<span class="hljs-number">0.004</span>
20-
<span class="hljs-symbol">N19</span> <span class="hljs-attr">#503</span>=[<span class="hljs-attr">#500</span>+<span class="hljs-attr">#501</span>]
21-
<span class="hljs-symbol">N20</span> <span class="hljs-attr">VC45</span>=<span class="hljs-number">0.0006</span>
22-
<span class="hljs-attr">VS4</span>=<span class="hljs-number">0.0007</span>
23-
<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>
24-
<span class="hljs-symbol">N22</span> <span class="hljs-name">G0</span> X<span class="hljs-number">5000</span>
25-
<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>
26-
<span class="hljs-symbol">N24</span> X<span class="hljs-number">-0.678</span> Y<span class="hljs-number">+.990</span>
27-
<span class="hljs-symbol">N25</span> <span class="hljs-name">G84.3</span> X<span class="hljs-number">-0.1</span>
28-
<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>
29-
<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>
30-
<span class="hljs-symbol">N28</span> <span class="hljs-attr">VZOFZ</span>=<span class="hljs-number">652.9658</span>
31-
<span class="hljs-meta">%</span>
12+
<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>
13+
<span class="hljs-operator">N12</span> <span class="hljs-property">Y-.990</span>
14+
<span class="hljs-operator">N13</span> <span class="hljs-title function_">G40</span>
15+
<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>
16+
<span class="hljs-operator">N15</span> <span class="hljs-title function_">G0</span> <span class="hljs-property">Z.1</span>
17+
<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>
18+
<span class="hljs-operator">N17</span> <span class="hljs-keyword">CALL</span> <span class="hljs-symbol">O9456</span>
19+
<span class="hljs-operator">N18</span> <span class="hljs-variable">#500</span>=<span class="hljs-number">0.004</span>
20+
<span class="hljs-operator">N19</span> <span class="hljs-variable">#503</span>=[<span class="hljs-variable">#500</span>+<span class="hljs-variable">#501</span>]
21+
<span class="hljs-operator">N20</span> VC45=<span class="hljs-number">0.0006</span>
22+
VS4=<span class="hljs-number">0.0007</span>
23+
<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>
24+
<span class="hljs-operator">N22</span> <span class="hljs-title function_">G0</span> <span class="hljs-property">X5000</span>
25+
<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>
26+
<span class="hljs-operator">N24</span> <span class="hljs-property">X-0.678</span> <span class="hljs-property">Y+.990</span>
27+
<span class="hljs-operator">N25</span> <span class="hljs-title function_">G84.3</span> <span class="hljs-property">X-0.1</span>
28+
<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>]
29+
<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>]
30+
<span class="hljs-operator">N28</span> VZOFZ=<span class="hljs-number">652.9658</span>
31+
<span class="hljs-keyword">%</span>

0 commit comments

Comments
 (0)