compiler: Updated toolchain for proper byte literal support
[nit.git] / src / literal.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Parsing of literal values in the abstract syntax tree.
18 module literal
19
20 import phase
21
22 redef class ToolContext
23 # Parses literal values in the whole AST and produces errors if needed
24 var literal_phase: Phase = new LiteralPhase(self, null)
25 end
26
27 private class LiteralPhase
28 super Phase
29
30 redef fun process_nmodule(nmodule) do nmodule.do_literal(toolcontext)
31 end
32
33 redef class AModule
34 # Visit the module to compute the real value of the literal-related node of the AST.
35 # Warnings and errors are displayed on the toolcontext.
36 fun do_literal(toolcontext: ToolContext)
37 do
38 var v = new LiteralVisitor(toolcontext)
39 v.enter_visit(self)
40 end
41 end
42
43 private class LiteralVisitor
44 super Visitor
45
46 var toolcontext: ToolContext
47
48 redef fun visit(n)
49 do
50 n.accept_literal(self)
51 n.visit_all(self)
52 end
53 end
54
55 redef class ANode
56 private fun accept_literal(v: LiteralVisitor) do end
57 end
58
59 redef class AExpr
60 # Get `self` as a `String`.
61 # Return null if not a string.
62 fun as_string: nullable String
63 do
64 if not self isa AStringFormExpr then return null
65 return self.value.as(not null)
66 end
67
68 # Get `self` as an `Int`.
69 # Return null if not an integer.
70 fun as_int: nullable Int
71 do
72 if not self isa AIntExpr then return null
73 return self.value.as(not null)
74 end
75
76 # Get `self` as a single identifier.
77 # Return null if not a single identifier.
78 fun as_id: nullable String
79 do
80 if self isa AMethidExpr then
81 return self.collect_text
82 end
83 if not self isa ACallExpr then return null
84 if not self.n_expr isa AImplicitSelfExpr then return null
85 if not self.n_args.n_exprs.is_empty then return null
86 return self.n_id.text
87 end
88 end
89
90 redef class Text
91 private fun remove_underscores: Text do
92 var b = new FlatBuffer
93 for i in chars do
94 if i == '_' then continue
95 b.add i
96 end
97 return b
98 end
99 end
100
101 redef class AIntExpr
102 # The value of the literal int once computed.
103 var value: nullable Int
104 end
105
106 redef class ADecIntExpr
107 redef fun accept_literal(v)
108 do
109 value = self.n_number.text.to_i
110 end
111 end
112
113 redef class AHexIntExpr
114 redef fun accept_literal(v)
115 do
116 var s = self.n_hex_number.text.substring_from(2).remove_underscores
117 if s.is_empty then
118 v.toolcontext.error(location, "Error: invalid hexadecimal literal")
119 return
120 end
121 value = s.to_hex
122 end
123 end
124
125 redef class ABinIntExpr
126 redef fun accept_literal(v)
127 do
128 var s = self.n_bin_number.text.substring_from(2).remove_underscores
129 if s.is_empty then
130 v.toolcontext.error(location, "Error: invalid binary literal")
131 return
132 end
133 value = s.to_bin
134 end
135 end
136
137 redef class AOctIntExpr
138 redef fun accept_literal(v)
139 do
140 var s = self.n_oct_number.text.substring_from(2).remove_underscores
141 if s.is_empty then
142 v.toolcontext.error(location, "Error: invalid octal literal")
143 return
144 end
145 value = s.to_oct
146 end
147 end
148
149 redef class AByteExpr
150 # The value of the literal int once computed.
151 var value: nullable Byte
152 end
153
154 redef class ADecByteExpr
155 redef fun accept_literal(v)
156 do
157 var t = self.n_bytenum.text
158 value = t.substring(0, t.length - 2).to_i.to_b
159 end
160 end
161
162 redef class AHexByteExpr
163 redef fun accept_literal(v)
164 do
165 var t = self.n_hex_bytenum.text
166 var s = t.substring(2, t.length - 4).remove_underscores
167 if s.is_empty then
168 v.toolcontext.error(location, "Error: invalid hexadecimal literal")
169 return
170 end
171 value = s.to_hex.to_b
172 end
173 end
174
175 redef class ABinByteExpr
176 redef fun accept_literal(v)
177 do
178 var t = self.n_bin_bytenum.text
179 var s = t.substring(2, t.length - 4).remove_underscores
180 if s.is_empty then
181 v.toolcontext.error(location, "Error: invalid binary literal")
182 return
183 end
184 value = s.to_bin.to_b
185 end
186 end
187
188 redef class AOctByteExpr
189 redef fun accept_literal(v)
190 do
191 var t = self.n_oct_bytenum.text
192 var s = t.substring(2, t.length - 4).remove_underscores
193 if s.is_empty then
194 v.toolcontext.error(location, "Error: invalid octal literal")
195 return
196 end
197 value = s.to_oct.to_b
198 end
199 end
200
201 redef class AFloatExpr
202 # The value of the literal float once computed.
203 var value: nullable Float
204 redef fun accept_literal(v)
205 do
206 self.value = self.n_float.text.to_f
207 end
208 end
209
210 redef class ACharExpr
211 # The value of the literal char once computed.
212 var value: nullable Char
213 redef fun accept_literal(v)
214 do
215 var txt = self.n_char.text.unescape_nit
216 if txt.length != 3 then
217 v.toolcontext.error(self.hot_location, "Syntax Error: invalid character literal `{txt}`.")
218 return
219 end
220 self.value = txt.chars[1]
221 end
222 end
223
224 redef class AStringFormExpr
225 # The value of the literal string once computed.
226 var value: nullable String
227 redef fun accept_literal(v)
228 do
229 var txt = self.n_string.text
230 var behead = 1
231 var betail = 1
232 if txt.chars[0] == txt.chars[1] and txt.length >= 6 then
233 behead = 3
234 betail = 3
235 if txt.chars[0] == '"' and txt.chars[3] == '\n' then behead = 4 # ignore first \n in """
236 end
237 self.value = txt.substring(behead, txt.length - behead - betail).unescape_nit
238 end
239 end