open StdLabels module S = Qsp_syntax.S module T = Qsp_syntax.T module Report = Qsp_syntax.Report let identifier = "escaped_string" let description = "Check for unnecessary use of expression encoded in string" let is_global = false let active = ref true let depends = [ Get_type.ex ] type ex = Qsp_syntax.Identifier.t type context = unit let initialize = Fun.id let finalize () = [] module Expression = struct type t = { type_of : Get_type.Expression.t; report : Report.t list } type t' = Report.t list let v : t -> t' = fun t -> t.report (** Identify the expressions reprented as string. That’s here that the report are added. All the rest of the module only push thoses warning to the top level. *) let literal : ctx:Qsp_syntax.S.extract_context -> S.pos -> t T.literal list -> t = fun ~ctx pos content -> let type_of = Option.get (ctx.f Get_type.expression_id) in match content with | [ T.Expression t; T.Text "" ] -> ( match Get_type.Expression.get_type t.type_of with | Get_type.Integer -> { type_of; report = [] } | _ -> let msg = Report.debug pos "This expression can be simplified" in { type_of; report = [ msg ] }) | _ -> { type_of; report = [] } let ident : ctx:Qsp_syntax.S.extract_context -> (S.pos, t) S.variable -> t = fun ~ctx variable -> let type_of = Option.get (ctx.f Get_type.expression_id) in match variable.index with None -> { type_of; report = [] } | Some t -> t let integer : ctx:Qsp_syntax.S.extract_context -> S.pos -> string -> t = fun ~ctx pos t -> ignore pos; ignore t; let type_of = Option.get (ctx.f Get_type.expression_id) in { type_of; report = [] } let function_ : ctx:Qsp_syntax.S.extract_context -> S.pos -> T.function_ -> t list -> t = fun ~ctx pos f expressions -> let type_of = Option.get (ctx.f Get_type.expression_id) in ignore pos; ignore f; let exprs = List.fold_left ~init:[] expressions ~f:(fun acc el -> List.rev_append el.report acc) in { type_of; report = exprs } let uoperator : ctx:Qsp_syntax.S.extract_context -> S.pos -> T.uoperator -> t -> t = fun ~ctx pos op r -> let type_of = Option.get (ctx.f Get_type.expression_id) in ignore op; ignore pos; { r with type_of } let boperator : ctx:Qsp_syntax.S.extract_context -> S.pos -> T.boperator -> t -> t -> t = fun ~ctx pos op r1 r2 -> let type_of = Option.get (ctx.f Get_type.expression_id) in ignore pos; ignore op; { type_of; report = r1.report @ r2.report } end module Instruction : S.Instruction with type t' = Report.t list and type expression = Expression.t' = struct type t = Report.t list (** Internal type used in the evaluation *) type t' = t let v : t -> t' = Fun.id type expression = Expression.t' let call : S.pos -> T.keywords -> expression list -> t = fun pos k exprs -> ignore pos; ignore k; List.concat exprs let location : S.pos -> string -> t = fun _ _ -> [] let comment : S.pos -> t = fun _ -> [] let expression : expression -> t = Fun.id let act : S.pos -> label:expression -> t list -> t = fun pos ~label instructions -> ignore pos; List.concat (label :: instructions) let fold_clause : (expression, t) S.clause -> t = fun (_pos1, expression, ts) -> List.concat (expression :: ts) let if_ : S.pos -> (expression, t) S.clause -> elifs:(expression, t) S.clause list -> else_:(S.pos * t list) option -> t = fun pos clause ~elifs ~else_ -> ignore pos; let init = match else_ with | None -> fold_clause clause | Some (_, ts) -> List.rev_append (fold_clause clause) (List.concat ts) in List.fold_left elifs ~init ~f:(fun t clause -> List.rev_append (fold_clause clause) t) let assign : S.pos -> (S.pos, expression) S.variable -> T.assignation_operator -> expression -> t = fun pos variable op expression -> ignore pos; ignore op; match variable.index with | None -> expression | Some v -> List.rev_append v expression end module Location = struct type t = Report.t list type instruction = Instruction.t' let v = Fun.id let location : unit -> S.pos -> instruction list -> t = fun () pos intructions -> ignore pos; List.concat intructions end