Browse Source

better parser for completion/resume.

Nicolas Cannasse 18 years ago
parent
commit
bc4f5cccf5
1 changed files with 93 additions and 29 deletions
  1. 93 29
      parser.ml

+ 93 - 29
parser.ml

@@ -28,6 +28,7 @@ type error_msg =
 
 exception Error of error_msg * pos
 exception TypePath of string list
+exception Display of expr
 
 let error_msg = function
 	| Unexpected t -> "Unexpected "^(s_token t)
@@ -51,6 +52,9 @@ let last_token s =
 
 let serror() = raise (Stream.Error "")
 
+let display e =
+	if !resume_display then raise (Display e) else serror()
+
 let priority = function
 	| OpAssign | OpAssignOp _ -> -4
 	| OpBoolOr -> -3
@@ -161,7 +165,11 @@ and parse_type_decl s =
 				d_flags = List.map snd c @ n;
 				d_data = l
 			}, punion p1 p2)
-		| [< n , p1 = parse_class_flags; doc = get_doc; '(Const (Type name),_); tl = parse_constraint_params; hl = psep Comma parse_class_herit; '(BrOpen,_); fl = plist parse_class_field; '(BrClose,p2) >] ->
+		| [< n , p1 = parse_class_flags; doc = get_doc; '(Const (Type name),_); tl = parse_constraint_params; hl = psep Comma parse_class_herit; '(BrOpen,_); fl = parse_class_field_resume; s >] ->
+			let p2 = (match s with parser
+				| [< '(BrClose,p2) >] -> p2
+				| [< >] -> if !resume_display then p1 else serror()
+			) in
 			(EClass {
 				d_name = name;
 				d_doc = doc;
@@ -180,6 +188,43 @@ and parse_type_decl s =
 
 and parse_package s = psep Dot ident s
 
+and parse_class_field_resume s =
+	if not !resume_display then
+		plist parse_class_field s
+	else
+		(* junk all tokens until we reach next variable/function or next type declaration *)
+		let rec loop() =
+			(match List.map fst (Stream.npeek 2 s) with
+			| Kwd Public :: _ | Kwd Static :: _ | Kwd Var :: _ | Kwd Override :: _ ->
+				raise Exit
+			| [] | Eof :: _ | Kwd Extern :: _ | Kwd Class :: _ |Kwd Enum :: _ | Kwd Typedef :: _ ->
+				raise Not_found
+			| [Kwd Private; Kwd Function]
+			| [Kwd Private; Kwd Var] ->
+				raise Exit
+			| [Kwd Private; Kwd Class]
+			| [Kwd Private; Kwd Enum]
+			| [Kwd Private; Kwd Typedef] ->
+				raise Not_found	
+			| [Kwd Function; Const _]
+			| [Kwd Function; Kwd New] ->
+				raise Exit
+			| _ -> ());
+			Stream.junk s;
+			loop();	
+		in
+		try
+			loop();
+		with
+			| Not_found ->
+				[]
+			| Exit ->
+				try 
+					let c = parse_class_field s in
+					c :: parse_class_field_resume s
+				with
+					Stream.Error _ | Stream.Failure -> parse_class_field_resume s
+
 and parse_import acc = parser
 	| [< '(Const (Ident k),_); '(Dot,_); s >] ->
 		parse_import (k :: acc) s
@@ -301,14 +346,14 @@ and parse_class_field s =
 				(FProp (name,doc,l,i1,i2,t),punion p1 p2)
 			| [< t = parse_type_opt; s >] ->
 				let e , p2 = (match s with parser
-				| [< '(Binop OpAssign,_) when List.mem AStatic l; e = expr; p2 = semicolon >] -> Some e , p2
+				| [< '(Binop OpAssign,_) when List.mem AStatic l; e = toplevel_expr; p2 = semicolon >] -> Some e , p2
 				| [< '(Semicolon,p2) >] -> None , p2
 				| [< >] -> serror()
 				) in
 				(FVar (name,doc,l,t,e),punion p1 p2))
 		| [< '(Kwd Function,p1); name = parse_fun_name; pl = parse_constraint_params; '(POpen,_); al = psep Comma parse_fun_param; '(PClose,_); t = parse_type_opt; s >] ->
 			let e = (match s with parser
-				| [< e = expr >] -> e
+				| [< e = toplevel_expr >] -> e
 				| [< '(Semicolon,p) >] -> (EBlock [],p)
 				| [< >] -> serror()
 			) in
@@ -378,34 +423,36 @@ and parse_class_herit = parser
 and block1 = parser
 	| [< '(Const (Ident name),p); s >] -> block2 name true p s
 	| [< '(Const (Type name),p); s >] -> block2 name false p s
-	| [< b = block >] -> EBlock b
+	| [< b = block [] >] -> EBlock b
 
 and block2 name ident p = parser
 	| [< '(DblDot,_); e = expr; l = parse_obj_decl >] -> EObjectDecl ((name,e) :: l)
 	| [< e = expr_next (EConst (if ident then Ident name else Type name),p); s >] ->
 		try
 			let _ = semicolon s in
-			let b = block s in
+			let b = block [] s in
 			EBlock (e :: b)
 		with
 			| Error (e,p) ->
 				(!display_error) e p;
-				EBlock (block s)
+				EBlock (block [] s)
 
-and block s =
-	try
+and block acc s =
+	try		
 		let e = parse_block_elt s in
-		e :: block s
+		block (e :: acc) s
 	with
+		| Display e ->
+			display (EBlock (List.rev (e :: acc)),snd e)
 		| Stream.Failure ->
-			[]
+			List.rev acc
 		| Stream.Error _ ->
 			let tk , pos = (match Stream.peek s with None -> last_token s | Some t -> t) in
 			(!display_error) (Unexpected tk) pos;
-			block s
+			block acc s
         | Error (e,p) ->
 			(!display_error) e p;
-			block s
+			block acc s
 
 and parse_block_elt = parser
 	| [< '(Kwd Var,p1); vl = psep Comma parse_var_decl; p2 = semicolon >] -> (EVars vl,punion p1 p2)
@@ -463,8 +510,12 @@ and expr = parser
 		expr_next (EFunction f, punion p1 (pos e)) s
 	| [< '(Unop op,p1) when is_prefix op; e = expr >] -> make_unop op e p1
 	| [< '(Binop OpSub,p1); e = expr >] -> make_unop Neg e p1
-	| [< '(Kwd For,p); '(POpen,_); name = any_ident; '(Kwd In,_); it = expr; '(PClose,_); e = expr; s >] ->
-		expr_next (EFor (name,it,e),punion p (pos e)) s
+	| [< '(Kwd For,p); '(POpen,_); name = any_ident; '(Kwd In,_); it = expr; '(PClose,_); s >] ->
+		(try
+			let e = expr s in
+			expr_next (EFor (name,it,e),punion p (pos e)) s
+		with
+			Display e -> display (EFor (name,it,e),punion p (pos e)))
 	| [< '(Kwd If,p); '(POpen,_); cond = expr; '(PClose,_); e1 = expr; s >] ->
 		let e2 , s = (match s with parser
 			| [< '(Kwd Else,_); e2 = expr; s >] -> Some e2 , s
@@ -485,21 +536,21 @@ and expr = parser
 	| [< '(Kwd Continue,p) >] -> (EContinue,p)
 	| [< '(Kwd While,p1); '(POpen,_); cond = expr; '(PClose,_); e = expr; s >] -> expr_next (EWhile (cond,e,NormalWhile),punion p1 (pos e)) s
 	| [< '(Kwd Do,p1); e = expr; '(Kwd While,_); '(POpen,_); cond = expr; '(PClose,_); s >] -> expr_next (EWhile (cond,e,DoWhile),punion p1 (pos e)) s
-	| [< '(Kwd Switch,p1); e = expr; '(BrOpen,_); cases , def = parse_switch_cases; '(BrClose,p2); s >] -> expr_next (ESwitch (e,cases,def),punion p1 p2) s
-	| [< '(Kwd Try,p1); e = expr; cl = plist parse_catch; s >] -> expr_next (ETry (e,cl),p1) s
+	| [< '(Kwd Switch,p1); e = expr; '(BrOpen,_); cases , def = parse_switch_cases e []; '(BrClose,p2); s >] -> expr_next (ESwitch (e,cases,def),punion p1 p2) s
+	| [< '(Kwd Try,p1); e = expr; cl = plist (parse_catch e); s >] -> expr_next (ETry (e,cl),p1) s
 	| [< '(IntInterval i,p1); e2 = expr >] -> make_binop OpInterval (EConst (Int i),p1) e2
 	| [< '(Kwd Untyped,p1); e = expr >] -> (EUntyped e,punion p1 (pos e))
 
 and expr_next e1 = parser
 	| [< '(Dot,p); s >] ->
 		(match s with parser
-		| [< '(Const (Ident f),p); s >] -> expr_next (EField (e1,f) , punion (pos e1) p) s
-		| [< '(Const (Type t),p); s >] -> expr_next (EType (e1,t) , punion (pos e1) p) s
-		| [< >] -> if !resume_display then (EDisplay e1, p) else serror())
+		| [< '(Const (Ident f),p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,f) , punion (pos e1) p2) s
+		| [< '(Const (Type t),p2) when p.pmax = p2.pmin; s >] -> expr_next (EType (e1,t) , punion (pos e1) p2) s
+		| [< >] -> display (EDisplay e1,p))
 	| [< '(POpen,p1); params = psep Comma expr; s >] ->
 		(match s with parser
 		| [< '(PClose,p2); s >] -> expr_next (ECall (e1,params) , punion (pos e1) p2) s
-		| [< >] -> if !resume_display then (EDisplay e1,p1) else serror())
+		| [< >] -> display (EDisplay e1,p1))
 	| [< '(BkOpen,_); e2 = expr; '(BkClose,p2); s >] ->
 		expr_next (EArray (e1,e2), punion (pos e1) p2) s
 	| [< '(Binop OpGt,_); s >] ->
@@ -527,21 +578,34 @@ and expr_next e1 = parser
 		expr_next (EUnop (op,Postfix,e1), punion (pos e1) p) s
 	| [< >] -> e1
 
-and parse_switch_cases = parser
-	| [< '(Kwd Default,p1); '(DblDot,_); e = block1; l , def = parse_switch_cases >] ->
+and parse_switch_cases eswitch cases = parser
+	| [< '(Kwd Default,p1); '(DblDot,_); s >] ->
+		let b = (try block1 s with Display e -> display (ESwitch (eswitch,cases,Some e),p1)) in
+		let l , def = parse_switch_cases eswitch cases s in
 		(match def with None -> () | Some (e,p) -> error Duplicate_default p);
-		l , Some (e , p1)
-	| [< '(Kwd Case,p1); el = psep Comma expr; '(DblDot,_); b = block1; l , def = parse_switch_cases >] ->
-		(el,(b,p1)) :: l , def
+		l , Some (b,p1)
+	| [< '(Kwd Case,p1); el = psep Comma expr; '(DblDot,_); s >] ->
+		let b = (try block1 s with Display e -> display (ESwitch (eswitch,List.rev ((el,e) :: cases),None),p1)) in
+		parse_switch_cases eswitch ((el,(b,p1)) :: cases) s
 	| [< >] ->
-		[] , None
+		List.rev cases , None
 
-and parse_catch = parser
-	| [< '(Kwd Catch,_); '(POpen,_); name = any_ident; s >] ->
+and parse_catch etry = parser
+	| [< '(Kwd Catch,p); '(POpen,_); name = any_ident; s >] ->
 		match s with parser
-		| [< '(DblDot,_); t = parse_type_path; '(PClose,_); e = expr >] -> (name,t,e)
+		| [< '(DblDot,_); t = parse_type_path; '(PClose,_); s >] ->
+			(try
+				(name,t,expr s)
+			with
+				Display e -> display (ETry (etry,[name,t,e]),p))
 		| [< '(_,p) >] -> error Missing_type p
 
+and toplevel_expr s =
+	try
+		expr s
+	with
+		Display e -> e
+
 let parse code file =
 	let old = Lexer.save() in
 	let old_cache = !cache in