From 0c71f5790535f52355d793a29a0edf3aef30ad59 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sun, 11 Mar 2012 10:42:16 +0000 Subject: [PATCH] make the difference between "parse" and "parseInlineString" (substring error reporting + completion support) --- ast.ml | 64 +++++++++++++++++++++++++++++++++++++++ interp.ml | 8 ++--- std/haxe/macro/Context.hx | 11 +++++-- typer.ml | 26 +++++++++------- 4 files changed, 92 insertions(+), 17 deletions(-) diff --git a/ast.ml b/ast.ml index f650485abb6..1a23a935ef0 100755 --- a/ast.ml +++ b/ast.ml @@ -443,3 +443,67 @@ let unescape s = in loop false 0; Buffer.contents b + + +let map_expr loop (e,p) = + let opt f o = + match o with None -> None | Some v -> Some (f v) + in + let rec tparam = function + | TPType t -> TPType (ctype t) + | TPExpr e -> TPExpr (loop e) + and cfield f = + { f with cff_kind = (match f.cff_kind with + | FVar (t,e) -> FVar (opt ctype t, opt loop e) + | FFun f -> FFun (func f) + | FProp (get,set,t,e) -> FProp (get,set,ctype t,opt loop e)) + } + and ctype = function + | CTPath t -> CTPath (tpath t) + | CTFunction (cl,c) -> CTFunction (List.map ctype cl, ctype c) + | CTAnonymous fl -> CTAnonymous (List.map cfield fl) + | CTParent t -> CTParent (ctype t) + | CTExtend (t,fl) -> CTExtend (tpath t, List.map cfield fl) + | CTOptional t -> CTOptional (ctype t) + and func f = + { + f_params = List.map (fun (n,tl) -> n,List.map ctype tl) f.f_params; + f_args = List.map (fun (n,o,t,e) -> n,o,opt ctype t,opt loop e) f.f_args; + f_type = opt ctype f.f_type; + f_expr = opt loop f.f_expr; + } + and tpath t = { t with tparams = List.map tparam t.tparams } + in + let e = (match e with + | EConst _ -> e + | EArray (e1,e2) -> EArray (loop e1, loop e2) + | EBinop (op,e1,e2) -> EBinop (op,loop e1, loop e2) + | EField (e,f) -> EField (loop e, f) + | EType (e,f) -> EType (loop e, f) + | EParenthesis e -> EParenthesis (loop e) + | EObjectDecl fl -> EObjectDecl (List.map (fun (f,e) -> f,loop e) fl) + | EArrayDecl el -> EArrayDecl (List.map loop el) + | ECall (e,el) -> ECall (loop e, List.map loop el) + | ENew (t,el) -> ENew (tpath t,List.map loop el) + | EUnop (op,f,e) -> EUnop (op,f,loop e) + | EVars vl -> EVars (List.map (fun (n,t,eo) -> n,opt ctype t,opt loop eo) vl) + | EFunction (n,f) -> EFunction (n,func f) + | EBlock el -> EBlock (List.map loop el) + | EFor (e1,e2) -> EFor (loop e1, loop e2) + | EIn (e1,e2) -> EIn (loop e1, loop e2) + | EIf (e,e1,e2) -> EIf (loop e, loop e1, opt loop e2) + | EWhile (econd,e,f) -> EWhile (loop econd, loop e, f) + | ESwitch (e,cases,def) -> ESwitch (loop e, List.map (fun (el,e) -> List.map loop el, loop e) cases, opt loop def) + | ETry (e, catches) -> ETry (loop e, List.map (fun (n,t,e) -> n,ctype t,loop e) catches) + | EReturn e -> EReturn (opt loop e) + | EBreak -> EBreak + | EContinue -> EContinue + | EUntyped e -> EUntyped (loop e) + | EThrow e -> EThrow (loop e) + | ECast (e,t) -> ECast (loop e,opt ctype t) + | EDisplay (e,f) -> EDisplay (loop e,f) + | EDisplayNew t -> EDisplayNew (tpath t) + | ETernary (e1,e2,e3) -> ETernary (loop e1,loop e2,loop e3) + | ECheckType (e,t) -> ECheckType (loop e, ctype t) + ) in + (e,p) \ No newline at end of file diff --git a/interp.ml b/interp.ml index 28e7a083b51..b949fd00837 100644 --- a/interp.ml +++ b/interp.ml @@ -92,7 +92,7 @@ type extern_api = { get_type : string -> Type.t option; get_module : string -> Type.t list; on_generate : (Type.t list -> unit) -> unit; - parse_string : string -> Ast.pos -> Ast.expr; + parse_string : string -> Ast.pos -> bool -> Ast.expr; typeof : Ast.expr -> Type.t; type_patch : string -> string -> bool -> string option -> unit; meta_patch : string -> string -> string option -> bool -> unit; @@ -1752,9 +1752,9 @@ let macro_lib = VNull | _ -> error() ); - "parse", Fun2 (fun s p -> - match s, p with - | VString s, VAbstract (APos p) -> encode_expr ((get_ctx()).curapi.parse_string s p) + "parse", Fun3 (fun s p b -> + match s, p, b with + | VString s, VAbstract (APos p), VBool b -> encode_expr ((get_ctx()).curapi.parse_string s p b) | _ -> error() ); "make_expr", Fun2 (fun v p -> diff --git a/std/haxe/macro/Context.hx b/std/haxe/macro/Context.hx index e1a4fed3bea..5b872aaf111 100644 --- a/std/haxe/macro/Context.hx +++ b/std/haxe/macro/Context.hx @@ -113,10 +113,17 @@ class Context { } /** - Parse an expression. + Parse a constructed string into the corresponding expression. **/ public static function parse( expr : String, pos : Position ) : Expr { - return load("parse", 2)(untyped expr.__s, pos); + return load("parse", 3)(untyped expr.__s, pos, false); + } + + /** + Parse a string contained into source code into the corresponding expression. Errors positions are reported within this string + **/ + public static function parseInlineString( expr : String, pos : Position ) : Expr { + return load("parse", 3)(untyped expr.__s, pos, true); } /** diff --git a/typer.ml b/typer.ml index f3a5f14a852..6b9b6959ed0 100644 --- a/typer.ml +++ b/typer.ml @@ -2188,24 +2188,27 @@ let get_type_patch ctx t sub = Hashtbl.add h k tp; tp -let parse_string ctx s p = +let parse_string ctx s p inlined = let old = Lexer.save() in let old_file = (try Some (Hashtbl.find Lexer.all_files p.pfile) with Not_found -> None) in + let old_display = !Parser.resume_display in let restore() = (match old_file with | None -> () | Some f -> Hashtbl.replace Lexer.all_files p.pfile f); + if not inlined then Parser.resume_display := old_display; Lexer.restore old; in Lexer.init p.pfile; + if not inlined then Parser.resume_display := null_pos; let _, decls = try Parser.parse ctx.com (Lexing.from_string s) - with Parser.Error (e,p) -> + with Parser.Error (e,pe) -> restore(); - error (Parser.error_msg e) p - | Lexer.Error (e,p) -> + error (Parser.error_msg e) (if inlined then pe else p) + | Lexer.Error (e,pe) -> restore(); - error (Lexer.error_msg e) p + error (Lexer.error_msg e) (if inlined then pe else p) in restore(); match decls with @@ -2268,12 +2271,13 @@ let make_macro_api ctx p = t() ) ); - Interp.parse_string = (fun s p -> + Interp.parse_string = (fun s p inl -> typing_timer ctx (fun() -> let head = "class X{static function main() " in let head = (if p.pmin > String.length head then head ^ String.make (p.pmin - String.length head) ' ' else head) in - match parse_string ctx (head ^ s ^ "}") p with - | EClass { d_data = [{ cff_name = "main"; cff_kind = FFun { f_expr = Some e } }]} -> e + let rec loop e = let e = Ast.map_expr loop e in (fst e,p) in + match parse_string ctx (head ^ s ^ "}") p inl with + | EClass { d_data = [{ cff_name = "main"; cff_kind = FFun { f_expr = Some e } }]} -> if inl then e else loop e | _ -> assert false ) ); @@ -2283,7 +2287,7 @@ let make_macro_api ctx p = Interp.type_patch = (fun t f s v -> typing_timer ctx (fun() -> let v = (match v with None -> None | Some s -> - match parse_string ctx ("typedef T = " ^ s) null_pos with + match parse_string ctx ("typedef T = " ^ s) null_pos false with | ETypedef { d_data = ct } -> Some ct | _ -> assert false ) in @@ -2294,7 +2298,7 @@ let make_macro_api ctx p = ); ); Interp.meta_patch = (fun m t f s -> - let m = (match parse_string ctx (m ^ " typedef T = T") null_pos with + let m = (match parse_string ctx (m ^ " typedef T = T") null_pos false with | ETypedef t -> t.d_meta | _ -> assert false ) in @@ -2603,7 +2607,7 @@ let call_macro ctx path meth args p = let call_init_macro ctx e = let p = { pfile = "--macro"; pmin = 0; pmax = 0 } in let api = make_macro_api ctx p in - let e = api.Interp.parse_string e p in + let e = api.Interp.parse_string e p false in match fst e with | ECall (e,args) -> let rec loop e =