Skip to content

Commit 4b0d10b

Browse files
Resolves #12
1 parent aaf9b33 commit 4b0d10b

File tree

3 files changed

+141
-6
lines changed

3 files changed

+141
-6
lines changed

grammar.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ module.exports = grammar({
4343

4444
externals: $ => [
4545
$.ident,
46+
$.annotation_ident,
4647

4748
'NULL',
4849
'abstract',
@@ -114,6 +115,7 @@ module.exports = grammar({
114115
$.state_decl_stmt,
115116
$.struct_decl_stmt,
116117
$.enum_decl_stmt,
118+
$.member_var_decl_stmt, // needed for @addField annotation
117119
$.nop
118120
)),
119121

@@ -299,6 +301,7 @@ module.exports = grammar({
299301
),
300302

301303
member_var_decl_stmt: $ => seq(
304+
field('annotation', optional($.annotation)),
302305
field('specifiers', repeat($.specifier)),
303306
$._var_decl_intro,
304307
':',
@@ -310,6 +313,7 @@ module.exports = grammar({
310313
// FUNCTION DECLARATION ================
311314

312315
event_decl_stmt: $ => seq(
316+
field('annotation', optional($.annotation)),
313317
$._event_decl_intro,
314318
field('params', $.func_params),
315319
optional(seq(
@@ -324,6 +328,7 @@ module.exports = grammar({
324328
),
325329

326330
func_decl_stmt: $ => seq(
331+
field('annotation', optional($.annotation)),
327332
field('specifiers', repeat($.specifier)),
328333
field('flavour', optional($.func_flavour)),
329334
$._func_decl_intro,
@@ -357,6 +362,13 @@ module.exports = grammar({
357362
),
358363

359364

365+
annotation: $ => seq(
366+
field('name', $.annotation_ident),
367+
optional($._annotation_arg)
368+
),
369+
370+
_annotation_arg: $ => seq('(', field('arg', $.ident), ')'),
371+
360372
func_flavour: $ => choice(
361373
'cleanup',
362374
'entry',

src/scanner.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@
3131

3232
// Do NOT change the order of values in TokenType and KEYWORDS
3333
// Keywords have to be sorted according to the ASCII table for the binary search to work (so those with capital letters have to go first)
34-
// Non keyword tokens go first (here it's just IDENT)
34+
// Non keyword tokens go first
3535

3636
enum TokenType {
3737
IDENT,
38+
ANNOTATION_IDENT,
3839

3940
KW_NULL,
4041
KW_ABSTRACT,
@@ -94,7 +95,8 @@ enum TokenType {
9495
_MAX_TOKENS
9596
};
9697

97-
#define KEYWORD_COUNT _MAX_TOKENS - 1
98+
#define FIRST_KEYWORD KW_NULL
99+
#define KEYWORD_COUNT _MAX_TOKENS - FIRST_KEYWORD
98100
static const char * const KEYWORDS[KEYWORD_COUNT] = {
99101
"NULL",
100102
"abstract",
@@ -188,7 +190,7 @@ static bool scan_ident(TSLexer *lexer, char* buffer, int buffer_size) {
188190
lexer->advance(lexer, true);
189191
}
190192

191-
if (lexer->eof(lexer) || !(isalpha(lexer->lookahead) || lexer->lookahead == '_')) {
193+
if (lexer->eof(lexer) || !(isalpha(lexer->lookahead) || lexer->lookahead == '_' || lexer->lookahead == '@')) {
192194
return false;
193195
}
194196

@@ -204,6 +206,10 @@ static bool scan_ident(TSLexer *lexer, char* buffer, int buffer_size) {
204206
lexer->advance(lexer, false);
205207
}
206208

209+
if (i == 1 && buffer[0] == '@') {
210+
return false;
211+
}
212+
207213
return true;
208214
}
209215

@@ -218,15 +224,16 @@ void tree_sitter_witcherscript_external_scanner_deserialize(void *p, const char
218224

219225
bool tree_sitter_witcherscript_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) {
220226
bool expected_ident = valid_symbols[IDENT];
227+
bool expected_annot_ident = valid_symbols[ANNOTATION_IDENT];
221228
bool expected_keyword = false;
222-
for(int i = IDENT + 1; i < _MAX_TOKENS; i++) {
229+
for(int i = FIRST_KEYWORD; i < _MAX_TOKENS; i++) {
223230
if(valid_symbols[i]) {
224231
expected_keyword = true;
225232
break;
226233
}
227234
}
228235

229-
if(expected_ident || expected_keyword) {
236+
if(expected_ident || expected_annot_ident || expected_keyword) {
230237
char buffer[MAX_IDENT_LENGTH] = {0};
231238

232239
if(scan_ident(lexer, buffer, MAX_IDENT_LENGTH)) {
@@ -243,7 +250,10 @@ bool tree_sitter_witcherscript_external_scanner_scan(void *payload, TSLexer *lex
243250
} else {
244251
return false;
245252
}
246-
} else if (expected_ident) {
253+
} else if (expected_annot_ident && buffer[0] == '@') {
254+
lexer->result_symbol = ANNOTATION_IDENT;
255+
return true;
256+
} else if (expected_ident && buffer[0] != '@') {
247257
lexer->result_symbol = IDENT;
248258
return true;
249259
}

test/corpus/annotations.txt

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
===================================================================================================
2+
Annotations
3+
===================================================================================================
4+
5+
6+
@wrapMethod(CPlayer)
7+
function CheatGod2(on : bool)
8+
{
9+
wrappedMethod(on); // this will call the original CheatGod2
10+
thePlayer.AddMoney(300);
11+
}
12+
13+
@addMethod(CPlayer)
14+
public function scriptextAdd()
15+
{
16+
dummy = 12345;
17+
}
18+
19+
@replaceMethod(CPlayer)
20+
function CheatGod2(on : bool)
21+
{
22+
thePlayer.AddMoney(2000);
23+
}
24+
25+
@replaceMethod
26+
function klapaucius()
27+
{
28+
thePlayer.AddMoney(1000);
29+
}
30+
31+
@addField(CPlayer)
32+
public var dummy: int;
33+
34+
35+
---------------------------------------------------------------------------------------------------
36+
37+
(script
38+
(func_decl_stmt
39+
annotation: (annotation
40+
name: (annotation_ident)
41+
arg: (ident))
42+
name: (ident)
43+
params: (func_params
44+
(func_param_group
45+
names: (ident)
46+
param_type: (type_annot
47+
type_name: (ident))))
48+
definition: (func_block
49+
(expr_stmt
50+
(func_call_expr
51+
func: (ident)
52+
args: (func_call_args
53+
(ident))))
54+
(comment)
55+
(expr_stmt
56+
(func_call_expr
57+
func: (member_field_expr
58+
accessor: (ident)
59+
member: (ident))
60+
args: (func_call_args
61+
(literal_int))))))
62+
(func_decl_stmt
63+
annotation: (annotation
64+
name: (annotation_ident)
65+
arg: (ident))
66+
specifiers: (specifier)
67+
name: (ident)
68+
params: (func_params)
69+
definition: (func_block
70+
(expr_stmt
71+
(assign_op_expr
72+
left: (ident)
73+
op: (assign_op_direct)
74+
right: (literal_int)))))
75+
(func_decl_stmt
76+
annotation: (annotation
77+
name: (annotation_ident)
78+
arg: (ident))
79+
name: (ident)
80+
params: (func_params
81+
(func_param_group
82+
names: (ident)
83+
param_type: (type_annot
84+
type_name: (ident))))
85+
definition: (func_block
86+
(expr_stmt
87+
(func_call_expr
88+
func: (member_field_expr
89+
accessor: (ident)
90+
member: (ident))
91+
args: (func_call_args
92+
(literal_int))))))
93+
(func_decl_stmt
94+
annotation: (annotation
95+
name: (annotation_ident))
96+
name: (ident)
97+
params: (func_params)
98+
definition: (func_block
99+
(expr_stmt
100+
(func_call_expr
101+
func: (member_field_expr
102+
accessor: (ident)
103+
member: (ident))
104+
args: (func_call_args
105+
(literal_int))))))
106+
(member_var_decl_stmt
107+
annotation: (annotation
108+
name: (annotation_ident)
109+
arg: (ident))
110+
specifiers: (specifier)
111+
names: (ident)
112+
var_type: (type_annot
113+
type_name: (ident))))

0 commit comments

Comments
 (0)