X-Git-Url: http://nitlanguage.org diff --git a/src/parser_util.nit b/src/parser_util.nit index f9ea467..f23ccda 100644 --- a/src/parser_util.nit +++ b/src/parser_util.nit @@ -15,7 +15,7 @@ # Utils and tools related to parsers and AST module parser_util -import parser +intrude import parser import toolcontext redef class ToolContext @@ -69,7 +69,7 @@ redef class ToolContext do var mod_string = "do\n{string}\nend" var nmodule = parse_module(mod_string) - var nblock = nmodule.n_classdefs.first.n_propdefs.first.as(AMainMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(ADoExpr).n_block.as(not null) + 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) return nblock end @@ -79,9 +79,158 @@ redef class ToolContext do var mod_string = "var dummy = \n{string}" var nmodule = parse_module(mod_string) - var nexpr = nmodule.n_classdefs.first.n_propdefs.first.as(AMainMethPropdef).n_block.as(ABlockExpr).n_expr.first.as(AVardeclExpr).n_expr.as(not null) + 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) return nexpr end + + # Try to parse the `string` as something + # + # Returns the first possible syntacticaly correct type among: + # + # - a type `AType` + # - a single `Token` + # - an expression `AExpr` + # - a block of statements `ABlockExpr` + # - a full module `AModule` + # - a `AError` if nothing else matches + # + # var tc = new ToolContext + # assert tc.parse_something("foo") isa TId + # assert tc.parse_something("foo[bar]") isa AExpr + # assert tc.parse_something("Foo[Bar]") isa AType + # assert tc.parse_something("foo\nbar") isa ABlockExpr + # assert tc.parse_something("fun foo do bar\nfoo") isa AModule + # assert tc.parse_something("fun fun") isa AParserError + # assert tc.parse_something("?%^&") isa ALexerError + fun parse_something(string: String): ANode + do + var source = new SourceFile.from_string("", string) + var error + var tree + var eof + var lexer + + lexer = new InjectedLexer(source) + lexer.injected_before.add new TKwvar + lexer.injected_before.add new TId + lexer.injected_before.add new TColumn + lexer.injected_before.add new TClassid + lexer.injected_before.add new TObra + lexer.injected_after.add new TCbra + tree = (new Parser(lexer)).parse + eof = tree.n_eof + if not eof isa AError then + 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 + ntype.parent = null + return ntype + end + error = eof + + lexer = new Lexer(source) + var first = lexer.next + if first isa EOF then return first + var second = lexer.next + if second isa EOF and not second isa AError then + first.parent = null + return first + end + + lexer = new InjectedLexer(source) + lexer.injected_before.add new TKwvar + lexer.injected_before.add new TId + lexer.injected_before.add new TAssign + lexer.injected_before.add new TOpar + lexer.injected_after.add new TCpar + tree = (new Parser(lexer)).parse + eof = tree.n_eof + if not eof isa AError then + 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 + nexpr.parent = null + return nexpr + end + if eof.location > error.location then error = eof + + lexer = new InjectedLexer(source) + lexer.injected_before.add new TKwdo + lexer.injected_before.add new TEol + lexer.injected_after.add new TEol + lexer.injected_after.add new TKwend + tree = (new Parser(lexer)).parse + eof = tree.n_eof + if not eof isa AError then + 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) + nblock.n_kwend = null # drop injected token + nblock.parent = null + return nblock + end + if eof.location > error.location then error = eof + + lexer = new Lexer(source) + tree = (new Parser(lexer)).parse + eof = tree.n_eof + if not eof isa AError then + return tree.n_base.as(not null) + end + if eof.location > error.location then error = eof + + return error + end + + # Parse the input of the user as something + fun interactive_parse(prompt: String): ANode + do + var oldtext = "" + + loop + printn prompt + printn " " + var s = sys.stdin.read_line + if s == "" then continue + if s.chars.first == ':' then + var res = new TString + res.text = s + return res + end + + var text = oldtext + s + "\n" + oldtext = "" + var n = parse_something(text) + + if n isa AParserError and n.token isa EOF then + # Unexpected end of file, thus continuing + if oldtext == "" then prompt = "." * prompt.length + oldtext = text + continue + end + + return n + end + end +end + +class InjectedLexer + super Lexer + + var injected_before = new List[Token] + var injected_after = new List[Token] + private var is_finished = false + + redef fun get_token + do + if not injected_before.is_empty then + var tok = injected_before.shift + return tok + end + if not is_finished then + var next = super + if not next isa EOF then return next + injected_after.push(next) + is_finished = true + end + + var tok = injected_after.shift + return tok + end end redef class ANode @@ -92,6 +241,15 @@ redef class ANode v.enter_visit(self) return v.result end + + # Return an array of node that are annotated + # The attached node can be retrieved by two invocation of parent + fun collect_annotations_by_name(name: String): Array[AAnnotation] + do + var v = new CollectAnnotationsByNameVisitor(name) + v.enter_visit(self) + return v.result + end end private class CollectTokensByTextVisitor @@ -101,8 +259,19 @@ private class CollectTokensByTextVisitor var result = new Array[Token] redef fun visit(node) do - if node == null then return node.visit_all(self) if node isa Token and node.text == text then result.add(node) end end + +private class CollectAnnotationsByNameVisitor + super Visitor + var name: String + init(name: String) do self.name = name + var result = new Array[AAnnotation] + redef fun visit(node) + do + node.visit_all(self) + if node isa AAnnotation and node.n_atid.n_id.text == name then result.add(node) + end +end