Merge: doc: fixed some typos and other misc. corrections
[nit.git] / src / parser_util.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Utils and tools related to parsers and AST
16 module parser_util
17
18 intrude import parser
19 import toolcontext
20
21 redef class ToolContext
22 # Parse a full module given as a string
23 # Fatal error if the `string` is not a syntactically correct module
24 fun parse_module(string: String): AModule
25 do
26 var source = new SourceFile.from_string("", string)
27 var lexer = new Lexer(source)
28 var parser = new Parser(lexer)
29 var tree = parser.parse
30
31 var eof = tree.n_eof
32 if eof isa AError then
33 self.fatal_error(null, "Fatal Error: {eof.message}.")
34 abort
35 end
36 return tree.n_base.as(not null)
37 end
38
39 # Parse a full classdef given as a string
40 # Fatal error if the `string` is not a syntactically correct class definition
41 fun parse_classdef(string: String): AClassdef
42 do
43 var nmodule = parse_module(string)
44 var nclassdefs = nmodule.n_classdefs
45 if nclassdefs.length != 1 then
46 self.fatal_error(null, "Fatal Error: not a classdef.")
47 abort
48 end
49 return nclassdefs.first
50 end
51
52 # Parse a full propdef given as a string
53 # Fatal error if the `string` is not a syntactically correct property definition
54 fun parse_propdef(string: String): APropdef
55 do
56 var mod_string = "class Dummy\n{string}\nend"
57 var nclassdef = parse_classdef(mod_string)
58 var npropdefs = nclassdef.n_propdefs
59 if npropdefs.length != 1 then
60 self.fatal_error(null, "Fatal Error: not a propdef.")
61 abort
62 end
63 return npropdefs.first
64 end
65
66 # Parse a full statement block given as a string
67 # Fatal error if the `string` is not a syntactically correct statement block
68 fun parse_stmts(string: String): AExpr
69 do
70 var mod_string = "do\n{string}\nend"
71 var nmodule = parse_module(mod_string)
72 var nblock = nmodule.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(ADoExpr).n_block.as(not null)
73 return nblock
74 end
75
76 # Parse a full expression given as a string
77 # Fatal error if the `string` is not a syntactically correct expression
78 fun parse_expr(string: String): AExpr
79 do
80 var mod_string = "var dummy = \n{string}"
81 var nmodule = parse_module(mod_string)
82 var nexpr = nmodule.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_expr.as(not null)
83 return nexpr
84 end
85
86 # Parse a super class declaration
87 # Fatal error if the `string` is not a syntactically correct super class declaration
88 fun parse_superclass(string: String): APropdef
89 do
90 var mod_string = "class Dummy\nsuper {string}\nend"
91 var nclassdef = parse_classdef(mod_string).as(AStdClassdef)
92 var nsuperclasses = nclassdef.n_propdefs
93 if nsuperclasses.length != 1 then
94 self.fatal_error(null, "Fatal Error: not a super class declaration.")
95 abort
96 end
97 return nsuperclasses.first
98 end
99
100 # Try to parse the `string` as something
101 #
102 # Returns the first possible syntacticaly correct type among:
103 #
104 # - a type `AType`
105 # - a single `Token`
106 # - an expression `AExpr`
107 # - a block of statements `ABlockExpr`
108 # - a full module `AModule`
109 # - a `AError` if nothing else matches
110 #
111 # var tc = new ToolContext
112 # assert tc.parse_something("foo") isa TId
113 # assert tc.parse_something("foo[bar]") isa AExpr
114 # assert tc.parse_something("Foo[Bar]") isa AType
115 # assert tc.parse_something("foo\nbar") isa ABlockExpr
116 # assert tc.parse_something("fun foo do bar\nfoo") isa AModule
117 # assert tc.parse_something("fun fun") isa AParserError
118 # assert tc.parse_something("?%^&") isa ALexerError
119 fun parse_something(string: String): ANode
120 do
121 var source = new SourceFile.from_string("", string)
122 var error
123 var tree
124 var eof
125 var lexer
126
127 lexer = new InjectedLexer(source)
128 lexer.injected_before.add new TKwvar
129 lexer.injected_before.add new TId
130 lexer.injected_before.add new TColumn
131 lexer.injected_before.add new TClassid
132 lexer.injected_before.add new TObra
133 lexer.injected_after.add new TCbra
134 tree = (new Parser(lexer)).parse
135 eof = tree.n_eof
136 if not eof isa AError then
137 var ntype = tree.n_base.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_type.n_types.first
138 ntype.parent = null
139 return ntype
140 end
141 error = eof
142
143 lexer = new Lexer(source)
144 var first = lexer.next
145 if first isa EOF then return first
146 var second = lexer.next
147 if second isa EOF and not second isa AError then
148 first.parent = null
149 return first
150 end
151
152 lexer = new InjectedLexer(source)
153 lexer.injected_before.add new TKwvar
154 lexer.injected_before.add new TId
155 lexer.injected_before.add new TAssign
156 lexer.injected_before.add new TOpar
157 lexer.injected_after.add new TCpar
158 tree = (new Parser(lexer)).parse
159 eof = tree.n_eof
160 if not eof isa AError then
161 var nexpr = tree.n_base.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_expr.as(AParExpr).n_expr
162 nexpr.parent = null
163 return nexpr
164 end
165 if eof.location > error.location then error = eof
166
167 lexer = new InjectedLexer(source)
168 lexer.injected_before.add new TKwdo
169 lexer.injected_before.add new TEol
170 lexer.injected_after.add new TEol
171 lexer.injected_after.add new TKwend
172 tree = (new Parser(lexer)).parse
173 eof = tree.n_eof
174 if not eof isa AError then
175 var nblock = tree.n_base.n_classdefs.first.n_propdefs.first.as(AMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(ADoExpr).n_block.as(ABlockExpr)
176 nblock.n_kwend = null # drop injected token
177 nblock.parent = null
178 return nblock
179 end
180 if eof.location > error.location then error = eof
181
182 lexer = new Lexer(source)
183 tree = (new Parser(lexer)).parse
184 eof = tree.n_eof
185 if not eof isa AError then
186 return tree.n_base.as(not null)
187 end
188 if eof.location > error.location then error = eof
189
190 return error
191 end
192
193 # Parse the input of the user as something
194 fun interactive_parse(prompt: String): ANode
195 do
196 var oldtext = ""
197
198 loop
199 printn prompt
200 printn " "
201 var s = sys.stdin.read_line
202 if s == "" then continue
203 if s.chars.first == ':' then
204 var res = new TString
205 res.text = s
206 return res
207 end
208
209 var text = oldtext + s + "\n"
210 oldtext = ""
211 var n = parse_something(text)
212
213 if n isa AParserError and n.token isa EOF then
214 # Unexpected end of file, thus continuing
215 if oldtext == "" then prompt = "." * prompt.length
216 oldtext = text
217 continue
218 end
219
220 return n
221 end
222 end
223 end
224
225 # A modified lexer that feed tokens before and after the real tokens.
226 class InjectedLexer
227 super Lexer
228
229 # The tokens to use before the real tokens (in order).
230 var injected_before = new List[Token]
231
232 # The tokens to use after the real tokens (in order).
233 # The real EOF token is produced after these tokens.
234 var injected_after = new List[Token]
235 private var is_finished = false
236
237 redef fun get_token
238 do
239 if not injected_before.is_empty then
240 var tok = injected_before.shift
241 return tok
242 end
243 if not is_finished then
244 var next = super
245 if not next isa EOF then return next
246 injected_after.push(next)
247 is_finished = true
248 end
249
250 var tok = injected_after.shift
251 return tok
252 end
253 end