1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # Parsing of literal values in the abstract syntax tree.
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)
27 private class LiteralPhase
30 redef fun process_nmodule
(nmodule
) do nmodule
.do_literal
(toolcontext
)
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)
38 var v
= new LiteralVisitor(toolcontext
)
43 private class LiteralVisitor
46 var toolcontext
: ToolContext
50 n
.accept_literal
(self)
56 private fun accept_literal
(v
: LiteralVisitor) do end
60 # Get `self` as a `String`.
61 # Return null if not a string.
62 fun as_string
: nullable String
64 if not self isa AStringFormExpr then return null
65 return self.value
.as(not null)
68 # Get `self` as an `Int`.
69 # Return null if not an integer.
70 fun as_int
: nullable Int
72 if not self isa AIntegerExpr then return null
73 return self.value
.as(not null).to_i
77 redef class AIntegerExpr
78 # The value of the literal int once computed.
79 var value
: nullable Numeric
81 redef fun accept_literal
(v
) do
82 value
= n_integer
.text
.to_num
84 v
.toolcontext
.error
(hot_location
, "Error: invalid literal `{n_integer.text}`")
89 redef class AFloatExpr
90 # The value of the literal float once computed.
91 var value
: nullable Float
92 redef fun accept_literal
(v
)
94 self.value
= self.n_float
.text
.to_f
98 # Any kind of literal which supports a prefix or a suffix
99 class AAugmentedLiteral
100 # Returns the text of the token
101 private fun text
: String is abstract
103 # Is the combination of prefixes and suffixes in `self` valid ?
104 fun is_valid_augmentation
: Bool is abstract
106 private fun delimiter_start
: Char is abstract
108 private fun delimiter_end
: Char is abstract
110 # Prefix for the entity, "" if no prefix is found
111 protected var prefix
: String is lazy
do return text
.substring
(0, text
.index_of
(delimiter_start
))
113 # Suffix for the entity, "" if no prefix is found
114 protected var suffix
: String is lazy
do return text
.substring_from
(text
.last_index_of
(delimiter_end
) + 1)
116 # Content of the entity, without prefix nor suffix
117 protected var content
: String is lazy
do return text
.substring_from
(text
.index_of
(delimiter_start
)).substring
(0, text
.last_index_of
(delimiter_end
) + 1)
120 redef class ACharExpr
121 super AAugmentedLiteral
122 # The value of the literal char once computed.
123 var value
: nullable Char = null
125 redef fun delimiter_start
do return '\''
127 redef fun delimiter_end do return '\
''
129 # Is the expression returning an ASCII byte value ?
130 fun is_ascii
: Bool do return prefix
== "b"
132 # Is the expression returning a Code Point ?
133 fun is_code_point
: Bool do return prefix
== "u"
135 redef fun text
do return n_char
.text
137 redef fun is_valid_augmentation
do
138 if suffix
!= "" then return false
139 if is_ascii
then return true
140 if is_code_point
then return true
141 if prefix
!= "" then return false
145 redef fun accept_literal
(v
)
147 if not is_valid_augmentation
then
148 v
.toolcontext
.error
(hot_location
, "Syntax Error: invalid prefix/suffix combination {prefix}/{suffix}")
151 var txt
= content
.unescape_nit
152 if txt
.length
!= 3 then
153 v
.toolcontext
.error
(self.hot_location
, "Syntax Error: invalid character literal `{txt}`.")
156 self.value
= txt
.chars
[1]
157 if is_ascii
and txt
.chars
[1].code_point
> 127 then v
.toolcontext
.error
(self.hot_location
, "Syntax Error: usage of byte prefix on multibyte character.")
161 redef class AStringFormExpr
162 # The value of the literal string once computed.
163 var value
: nullable String
164 redef fun accept_literal
(v
)
166 var txt
= self.n_string
.text
169 if txt
.chars
[0] == txt
.chars
[1] and txt
.length
>= 6 then
172 if txt
.chars
[0] == '"' and txt
.chars
[3] == '\n' then behead
= 4 # ignore first \n in """
174 self.value
= txt
.substring
(behead
, txt
.length
- behead
- betail
).unescape_nit