@@ -3,10 +3,34 @@ import { visitNode } from '../visit.js';
33import type * as Ast from '../../node.js' ;
44
55// 予約語となっている識別子があるかを確認する。
6- // - キーワードは字句解析の段階でそれぞれのKeywordトークンとなるため除外
6+ // - キーワードは字句解析の段階でそれぞれのKeywordトークンとなるが、エスケープシーケンスを含む場合はIdentifierトークンとなるので検証を行う。
77// - 文脈キーワードは識別子に利用できるため除外
88
99const reservedWord = [
10+ // 使用中の語
11+ 'null' ,
12+ 'true' ,
13+ 'false' ,
14+ 'each' ,
15+ 'for' ,
16+ 'loop' ,
17+ 'do' ,
18+ 'while' ,
19+ 'break' ,
20+ 'continue' ,
21+ 'match' ,
22+ 'case' ,
23+ 'default' ,
24+ 'if' ,
25+ 'elif' ,
26+ 'else' ,
27+ 'return' ,
28+ 'eval' ,
29+ 'var' ,
30+ 'let' ,
31+ 'exists' ,
32+
33+ // 使用予定の語
1034 'as' ,
1135 'async' ,
1236 'attr' ,
@@ -52,25 +76,36 @@ const reservedWord = [
5276 'new' ,
5377] ;
5478
55- function throwReservedWordError ( name : string , loc : Ast . Loc ) : void {
56- throw new AiScriptSyntaxError ( `Reserved word "${ name } " cannot be used as variable name.` , loc . start ) ;
79+ function validateName ( name : string , pos : Ast . Pos ) : void {
80+ if ( reservedWord . includes ( name ) ) {
81+ throwReservedWordError ( name , pos ) ;
82+ }
83+ }
84+
85+ function validateTypeName ( name : string , pos : Ast . Pos ) : void {
86+ if ( name === 'null' ) {
87+ return ;
88+ }
89+ validateName ( name , pos ) ;
90+ }
91+
92+ function throwReservedWordError ( name : string , pos : Ast . Pos ) : never {
93+ throw new AiScriptSyntaxError ( `Reserved word "${ name } " cannot be used as variable name.` , pos ) ;
5794}
5895
5996function validateDest ( node : Ast . Node ) : Ast . Node {
6097 return visitNode ( node , node => {
6198 switch ( node . type ) {
6299 case 'null' : {
63- throwReservedWordError ( node . type , node . loc ) ;
100+ throwReservedWordError ( node . type , node . loc . start ) ;
64101 break ;
65102 }
66103 case 'bool' : {
67- throwReservedWordError ( `${ node . value } ` , node . loc ) ;
104+ throwReservedWordError ( `${ node . value } ` , node . loc . start ) ;
68105 break ;
69106 }
70107 case 'identifier' : {
71- if ( reservedWord . includes ( node . name ) ) {
72- throwReservedWordError ( node . name , node . loc ) ;
73- }
108+ validateName ( node . name , node . loc . start ) ;
74109 break ;
75110 }
76111 }
@@ -81,9 +116,7 @@ function validateDest(node: Ast.Node): Ast.Node {
81116
82117function validateTypeParams ( node : Ast . Fn | Ast . FnTypeSource ) : void {
83118 for ( const typeParam of node . typeParams ) {
84- if ( reservedWord . includes ( typeParam . name ) ) {
85- throwReservedWordError ( typeParam . name , node . loc ) ;
86- }
119+ validateTypeName ( typeParam . name , node . loc . start ) ;
87120 }
88121}
89122
@@ -97,48 +130,46 @@ function validateNode(node: Ast.Node): Ast.Node {
97130 case 'attr' :
98131 case 'identifier' :
99132 case 'prop' : {
100- if ( reservedWord . includes ( node . name ) ) {
101- throwReservedWordError ( node . name , node . loc ) ;
102- }
133+ validateName ( node . name , node . loc . start ) ;
103134 break ;
104135 }
105136 case 'meta' : {
106- if ( node . name != null && reservedWord . includes ( node . name ) ) {
107- throwReservedWordError ( node . name , node . loc ) ;
137+ if ( node . name != null ) {
138+ validateName ( node . name , node . loc . start ) ;
108139 }
109140 break ;
110141 }
111142 case 'each' : {
112- if ( node . label != null && reservedWord . includes ( node . label ) ) {
113- throwReservedWordError ( node . label , node . loc ) ;
143+ if ( node . label != null ) {
144+ validateName ( node . label , node . loc . start ) ;
114145 }
115146 validateDest ( node . var ) ;
116147 break ;
117148 }
118149 case 'for' : {
119- if ( node . label != null && reservedWord . includes ( node . label ) ) {
120- throwReservedWordError ( node . label , node . loc ) ;
150+ if ( node . label != null ) {
151+ validateName ( node . label , node . loc . start ) ;
121152 }
122- if ( node . var != null && reservedWord . includes ( node . var ) ) {
123- throwReservedWordError ( node . var , node . loc ) ;
153+ if ( node . var != null ) {
154+ validateName ( node . var , node . loc . start ) ;
124155 }
125156 break ;
126157 }
127158 case 'loop' : {
128- if ( node . label != null && reservedWord . includes ( node . label ) ) {
129- throwReservedWordError ( node . label , node . loc ) ;
159+ if ( node . label != null ) {
160+ validateName ( node . label , node . loc . start ) ;
130161 }
131162 break ;
132163 }
133164 case 'break' : {
134- if ( node . label != null && reservedWord . includes ( node . label ) ) {
135- throwReservedWordError ( node . label , node . loc ) ;
165+ if ( node . label != null ) {
166+ validateName ( node . label , node . loc . start ) ;
136167 }
137168 break ;
138169 }
139170 case 'continue' : {
140- if ( node . label != null && reservedWord . includes ( node . label ) ) {
141- throwReservedWordError ( node . label , node . loc ) ;
171+ if ( node . label != null ) {
172+ validateName ( node . label , node . loc . start ) ;
142173 }
143174 break ;
144175 }
@@ -150,9 +181,7 @@ function validateNode(node: Ast.Node): Ast.Node {
150181 break ;
151182 }
152183 case 'namedTypeSource' : {
153- if ( reservedWord . includes ( node . name ) ) {
154- throwReservedWordError ( node . name , node . loc ) ;
155- }
184+ validateTypeName ( node . name , node . loc . start ) ;
156185 break ;
157186 }
158187 case 'fnTypeSource' : {
0 commit comments