model: new metamodel
[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 parser
21 import toolcontext
22
23 redef class AModule
24 # Visit the module to compute the real value of the literal-related node of the AST.
25 # Warnings and errors are displayed on the toolcontext.
26 fun do_literal(toolcontext: ToolContext)
27 do
28 var v = new LiteralVisitor(toolcontext)
29 v.enter_visit(self)
30 end
31 end
32
33 private class LiteralVisitor
34 super Visitor
35
36 var toolcontext: ToolContext
37
38 init(toolcontext: ToolContext)
39 do
40 self.toolcontext = toolcontext
41 end
42
43 redef fun visit(n)
44 do
45 if n != null then
46 n.accept_literal(self)
47 n.visit_all(self)
48 end
49 end
50 end
51
52 redef class ANode
53 private fun accept_literal(v: LiteralVisitor) do end
54 end
55
56 redef class AIntExpr
57 # The value of the literal int once computed.
58 var value: nullable Int
59 redef fun accept_literal(v)
60 do
61 self.value = self.n_number.text.to_i
62 end
63 end
64
65 redef class AFloatExpr
66 # The value of the literal float once computed.
67 var value: nullable Float
68 redef fun accept_literal(v)
69 do
70 # FIXME: no method to_f on string so just go ugly
71 var parts = self.n_float.text.split_with(".")
72 self.value = parts.first.to_i.to_f
73 end
74 end
75
76 redef class ACharExpr
77 # The value of the literal char once computed.
78 var value: nullable Char
79 redef fun accept_literal(v)
80 do
81 var txt = self.n_char.text.unescape_nit
82 if txt.length != 3 then
83 v.toolcontext.error(self.hot_location, "Invalid character literal {txt}")
84 return
85 end
86 self.value = txt[1]
87 end
88 end
89
90 redef class AStringFormExpr
91 # The value of the literal string once computed.
92 var value: nullable String
93 redef fun accept_literal(v)
94 do
95 var txt
96 if self isa AStringExpr then
97 txt = self.n_string.text
98 else if self isa AStartStringExpr then
99 txt = self.n_string.text
100 else if self isa AMidStringExpr then
101 txt = self.n_string.text
102 else if self isa AEndStringExpr then
103 txt = self.n_string.text
104 else abort
105 self.value = txt.substring(1, txt.length-2).unescape_nit
106 end
107 end
108
109 redef class String
110 # Return a string where Nit escape sequences are transformed.
111 #
112 # Example:
113 # var s = "\\n"
114 # print s.length # -> 2
115 # var u = s.unescape_nit
116 # print s.length # -> 1
117 # print s[0].ascii # -> 10 (the ASCII value of the "new line" character)
118 fun unescape_nit: String
119 do
120 var res = new Buffer.with_capacity(self.length)
121 var was_slash = false
122 for c in self do
123 if not was_slash then
124 if c == '\\' then
125 was_slash = true
126 else
127 res.add(c)
128 end
129 continue
130 end
131 was_slash = false
132 if c == 'n' then
133 res.add('\n')
134 else if c == 'r' then
135 res.add('\r')
136 else if c == 't' then
137 res.add('\t')
138 else if c == '0' then
139 res.add('\0')
140 else
141 res.add(c)
142 end
143 end
144 return res.to_s
145 end
146 end