shithub: martian9

ref: 689862826175d1b783f98018c1484c78396a33aa
dir: /macro.ml/

View raw version
module T = Types.Types

let gen_sym root =
  let gen () =
    match Random.int (26 + 26 + 10) with
    | n when n < 26 -> int_of_char 'a' + n
    | n when n < 26 + 26 -> int_of_char 'A' + n - 26
    | n -> int_of_char '0' + n - 26 - 26
  in
  let gen _ = String.make 1 (char_of_int (gen ())) in
  root ^ String.concat "" (Array.to_list (Array.init 5 gen))
;;

let rec is_matching_pattern sym pattern args matched =
  match pattern, args with
  (* literals and ellipses not handled, yet *)
  | ph :: pt, ah :: at ->
    (* print_endline "    LIST <-> LIST"; *)
    if ph = "_" || (ph = Printer.print sym true && sym = ah)
    then is_matching_pattern sym pt at matched && true
    else (* print_endline (" ------> " ^ ph ^ " vs " ^ Printer.print ah true); *)
      is_matching_pattern sym pt at matched
  | ph :: pt, [] ->
    (* print_endline "    LIST <-> []";
     * print_endline ("      ph: " ^ ph);
     * print_endline ("      pt: " ^ String.concat "|" pt); *)
    if ph = "_" || ph = Printer.print sym true
    then is_matching_pattern sym pt [] matched && true
    else ph = "..." || List.hd pt = "..."
  | [], ah :: at ->
    (* print_endline "    [] <-> LIST"; *)
    false
  | _, _ -> matched
;;

let rec ellipsis pattern template args =
  let has_ellipsis =
    try
      ignore (Str.search_forward (Str.regexp "...") (Printer.stringify pattern true) 0);
      true
    with
    | Not_found -> false
  in
  let ellipsis_substitutions = ref [] in
  let missing = List.length args - List.length pattern + if has_ellipsis then 1 else 0 in
  print_endline ("missing: " ^ string_of_int missing);
  (* print_endline (" NEED TO ADD " ^ string_of_int missing ^ " PLACEHOLDERS"); *)
  match missing with
  | _ when missing = 0 || missing > 0 ->
    (* add arguments *)
    print_endline ("ADD " ^ string_of_int missing ^ " arguments");
    for i = 1 to missing do
      ellipsis_substitutions := !ellipsis_substitutions @ [ gen_sym "x" ]
    done;
    let pattern_str =
      Str.global_replace
        (Str.regexp "\\.\\.\\.")
        (String.concat " " !ellipsis_substitutions)
        (Printer.stringify pattern true)
    in
    let template_str =
      Str.global_replace
        (Str.regexp "\\.\\.\\.")
        (String.concat " " !ellipsis_substitutions)
        (Printer.print template true)
    in
    (* let args_str = Printer.stringify args true in *)
    (* print_endline ("ellipsis: template: " ^ template_str ^ "  args: " ^ args_str); *)
    "(" ^ pattern_str ^ ") " ^ template_str ^ ")"
  | _ when missing < 0 ->
    (* remove ellipsis and arg *)
    print_endline "REMOVE arguments";
    (* let rgx = Str.regexp "[a-zA-Z0-9]+ \\.\\.\\." in *)
    let rgx = Str.regexp "[a-zA-Z0-9]+ \\.\\.\\." in
    let pattern_str = Str.global_replace rgx "" (Printer.stringify pattern true) in
    let template_str = Str.global_replace rgx "" (Printer.stringify pattern true) in
    print_endline ("  pattern:  " ^ Printer.dump pattern);
    print_endline ("    pattern_str:  " ^ pattern_str);
    print_endline ("  template: " ^ Printer.print template true);
    print_endline ("    template_str: " ^ template_str);
    print_endline ("(" ^ pattern_str ^ ") " ^ template_str ^ ")");
    "(" ^ pattern_str ^ ") " ^ template_str ^ ")"
  | _ -> "(" ^ Printer.dump pattern ^ ") " ^ Printer.print template true ^ ")"
;;

(* let lambdaize pattern template args =
 *   match pattern, args with
 *   | ph :: pt, ah :: at :: rest ->
 *     let expr = "((lambda " ^ ellipsis pt template args ^ Printer.stringify args false ^ ")" in
 *     print_endline ("  lambdaize list list: " ^ expr);
 *     Reader.read expr
 *   | ph :: pt, ah :: at ->
 *     let expr =
 *       "((lambda ("
 *       ^ Printer.stringify pt true
 *       ^ ")"
 *       ^ Printer.print template true
 *       ^ ")"
 *       ^ Printer.stringify args true
 *       ^ ")"
 *     in
 *     print_endline ("  lambdaize short list: " ^ expr);
 *     Reader.read expr
 *   | ph :: pt, [] ->
 *     let expr = "((lambda (" ^ Printer.stringify pt false ^ ") " ^ Printer.print template false ^ "))" in
 *     print_endline ("  lambdaize empty list: " ^ expr);
 *     Reader.read expr
 *   | _ ->
 *     print_endline "lambdaize: empty";
 *     Reader.read ("((lambda () " ^ Printer.print template true ^ "))")
 * ;; *)

(* let rec expand ast env args sym meta =
 *   print_endline ("\n\nTHIS IS A MACRO: " ^ Printer.print sym true);
 *   print_endline ("   META: " ^ Printer.print meta true);
 *   print_endline ("   ARGS: " ^ Printer.dump args);
 *   print_endline ("    AST: " ^ Printer.print ast true);
 *   match meta with
 *   | T.Map { T.value = m } ->
 *     ((\* let literals = Types.M9map.find Types.macro_literals m in *\)
 *     try
 *       let transformers = Types.M9map.find Types.macro_transformers m in
 *       print_endline
 *         ("  -- EVAL_MACRO: "
 *         (\*  ^ " literals: "
 *          * ^ Printer.print literals true *\)
 *         ^ "     transformers: "
 *         ^ Printer.print transformers true);
 *       let rec match_transform transforms =
 *         match transforms with
 *         | hd :: tl ->
 *           (\* print_endline ("      transform: " ^ Printer.print hd true); *\)
 *           (match hd with
 *           | T.List { T.value = [ T.List { T.value = pattern }; T.List { T.value = template } ] } ->
 *             (\* print_endline "   MULTI";
 *              * print_endline ("     - template: " ^ Printer.dump template); *\)
 *             print_endline
 *               ("      matched (m)?: "
 *               ^ (if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) (Core.seq ast) true
 *                 then "yes"
 *                 else "no")
 *               ^ " ::> "
 *               ^ Printer.dump pattern);
 *             if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) (Core.seq ast) true
 *             then lambdaize pattern (Types.list template) args
 *             else match_transform tl
 *           | T.List { T.value = [ T.List { T.value = pattern }; atom ] } ->
 *             (\* print_endline "   SINGLE"; *\)
 *             print_endline
 *               ("      matched (s)?: "
 *               ^ (if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) (Core.seq ast) true
 *                 then "yes"
 *                 else "no")
 *               ^ " ::> "
 *               ^ Printer.dump pattern);
 *             if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) (Core.seq ast) true
 *             then lambdaize pattern atom args
 *             else match_transform tl
 *           | _ -> raise (Utils.Syntax_error "Unknown"))
 *           (\* errors? *\)
 *         | [] -> raise (Utils.Syntax_error ("No matching transform for macro: '" ^ Printer.print sym true))
 *       in
 *       match_transform (Core.seq transformers)
 *     with
 *     | Not_found -> raise (Utils.Syntax_error ("'" ^ Printer.print sym true ^ "' is not a known macro")))
 *   | _ -> raise (Utils.Syntax_error "syntax error with defined macro")
 * ;; *)

(* let rec parse ast env args sym meta =
 *   print_endline("\n\nREADING MACRO: " ^ Printer.print sym true);
 *   match meta with
 *   | T.Map { T.value = m } ->
 *      (try
 *         let transformers = Types.M9map.find Types.macro_transformers m in
 *         let rec match_transform transforms =
 *           match transforms with
 *           | hd :: tl ->
 *              (match hd with
 *               | T.List { T.value = [ T.List { T.value = pattern }; T.List {T.value = template } ] } ->
 *                  if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) (Core.seq ast) true
 *                  then lambdaize pattern (Types.list template) args
 *                  else match_transform tl
 *               | T.List { T.value = [ T.List { T.value = pattern }; atom ] } ->
 *                  if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) (Core.seq ast) true
 *                  then lambdaize pattern atom args
 *                  else match_transform tl
 *               | _ -> raise (Utils.Syntax_error "no transform match"))
 *           | [] -> raise (Utils.Syntax_error ("No matching transform for macro: '" ^ Printer.print sym true))
 *         in
 *         match_transform (Core.seq transformers)
 *       with
 *       | Not_found -> raise (Utils.Syntax_error ("'" ^ Printer.print sym true ^ "' is not a known macro")))
 *   | _ -> raise (Utils.Syntax_error "syntax error with defined macro") *)

let rec parse ast macros =
  print_endline ("\n\nREADING MACRO: " ^ String.concat " " ast);
  match ast with
  | [] -> raise End_of_file
  | macro :: tokens -> print_endline ("   macro: " ^ macro)
;;

let add_variant sym variant env =
  let new_variant = gen_sym sym in
  match
    try Env.get env (Types.symbol sym) with
    | _ -> T.Nil
  with
  | T.Macro { T.value = sym; meta } ->
     (match meta with
      | T.Map { T.value = m } ->
         let variants = ref (Types.M9map.find Types.macro_variants m) in
         Types.M9map.add (Types.symbol new_variant) variant !variants;
         print_endline ("ADD_VARIANT: " ^ new_variant ^ ": " ^ Printer.print meta true);
         print_endline ("    variants: " ^ Printer.print !variants true)
      | _ -> raise (Utils.Runtime_error ("macro " ^ (Printer.print sym true) ^ " is missing its variants")))
  | _ -> raise (Utils.Syntax_error "add_variant botch")
;;

(* let macro = Env.get env (Types.symbol sym) in
 * let variants = Types.M9map.find Types.macro_variants macro.meta *)
(* match
 *   try Env.get env (Types.symbol sym) with
 *   | _ -> T.Nil
 * with
 * | T.Macro { T.value = sym; meta } ->
 *    let variants = Types.M9map.find Types.macro_variants meta in
 *    Types.M9map.add Types.macro_variants (new_variant :: variants) meta
 * | _ -> raise (Utils.Runtime_error ("wayward variant of " ^ sym ^ ": " ^ variant)) *)

let register_macro macro sym literals patterns env =
  let rec register_variants clauses =
    match clauses with
    | [ pattern ] ->
      print_endline ("  " ^ sym ^ ":  -> pattern: " ^ pattern);
      add_variant sym pattern env
    | pattern :: rest ->
      print_endline ("  " ^ sym ^ ":  pattern: " ^ pattern);
      print_endline ("  " ^ sym ^ ":  rest: " ^ String.concat " " rest);
      (* add_variant sym pattern env; *)
      register_variants rest
    | _ -> raise (Utils.Syntax_error "macro pattern registration botch")
  in
  (match
     try Env.get env (Types.symbol sym) with
     | _ -> T.Nil
   with
  | T.Nil ->
    print_endline ("new macro: " ^ sym);
    Env.set env (Types.symbol sym) macro
  | _ -> ());
  register_variants patterns
;;

(* match meta with
 * | T.Map { T.value = m } ->
 *    (try
 *       let transformers = Types.M9map.find Types.macro_transformers m in
 *       let rec match_transform transforms =
 *         match transforms with
 *         | hd :: tl ->
 *            (match hd with
 *             | T.List { T.value = [ T.List { T.value = pattern }; T.List {T.value = template } ] } ->
 *                if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) (Core.seq ast) true
 *                then lambdaize pattern (Types.list template) args
 *                else match_transform tl
 *             | T.List { T.value = [ T.List { T.value = pattern }; atom ] } ->
 *                if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) (Core.seq ast) true
 *                then lambdaize pattern atom args
 *                else match_transform tl
 *             | _ -> raise (Utils.Syntax_error "no transform match"))
 *         | [] -> raise (Utils.Syntax_error ("No matching transform for macro: '" ^ Printer.print sym true))
 *       in
 *       match_transform (Core.seq transformers)
 *     with
 *     | Not_found -> raise (Utils.Syntax_error ("'" ^ Printer.print sym true ^ "' is not a known macro")))
 * | _ -> raise (Utils.Syntax_error "syntax error with defined macro") *)