Commits

orbitz committed b253381

Added some more options for formatting code, code currently spits out comments and warns if they are too long

Comments (0)

Files changed (6)

 SOURCES = token.mli token.ml \
 	lexer.mli lexer.ml \
 	program_options.ml \
+	return.ml \
 	formatter.mli formatter.ml \
 	erlint.ml
 
 let parse_argv argv =
   let file_path = ref "" in
   let indent_spaces = ref 2 in
-  let params = 
+  let max_line_length = ref 80 in
+  let code_comment_ratio = ref 100 in
+  let params =
     Arg.align [ ( "-f"
 		, Arg.Set_string file_path
 		, "Path A file containing a list of paths to sequences (default stdin)."
 		, Arg.Set_int indent_spaces
 		, "Int Number of spaces to indent, default is 2"
 	        )
+	      ; ( "-max-line-length"
+		, Arg.Set_int max_line_length
+		, "Int Maximum number of characters per line (default 80)"
+	        )
+	      ; ( "-code-comment-ratio"
+		, Arg.Set_int code_comment_ratio
+		, "Int Number of lines of code per 1 line of comments (default 100)"
+	        )
 	      ]
   in
   Arg.parse params (fun _ -> ()) usage;
-  { Po.file_path = if !file_path = "" then None else Some !file_path 
+  { Po.file_path = if !file_path = "" then None else Some !file_path
   ; Po.indent_spaces = !indent_spaces
+  ; Po.max_line_length = !max_line_length
+  ; Po.code_comment_ratio = !code_comment_ratio
   }
 
 let list_of_stream stream =
   in
   list_of_stream' []
 
+let rec print_warnings = function
+  | [] -> ()
+  | warning::xs -> begin
+    Printf.printf "Line: %d\nMsg: %s\n"
+      warning.Formatter.line_number
+      warning.Formatter.msg;
+    print_warnings xs
+  end
+
+
 let main argv =
   let program_options = parse_argv argv in
-  let in_chan = 
+  let in_chan =
     match program_options.Po.file_path with
       | None -> stdin
       | Some path ->
   let code_stream = Stream.of_channel in_chan in
   let code_lexed = list_of_stream (Lexer.lex code_stream) in
   Token.pp_list code_lexed;
-  Formatter.format program_options stdout code_lexed
+  match Formatter.format program_options stdout code_lexed with
+    | Return.Success [] ->
+      Printf.printf "Success\n"
+    | Return.Success warnings -> begin
+      Printf.printf "%d warnings\n" (List.length warnings);
+      print_warnings warnings
+    end
+    | Return.Failure error ->
+      Printf.printf "Failed\nLine: %d\nMsg: %s\n"
+	error.Formatter.line_number
+	error.Formatter.msg
 
 
 let () = main Sys.argv
+open Token
+
+module Po = Program_options
+
+module R = Return
+
+type error = { line_number : int
+	     ; msg : string
+	     }
+
+type warning = error
+
+
+type function_info = { name : string
+		     ; spec : Token.t list
+		     }
+
 type parser_state =
   | Top_level
-  | Function
+  | Function of function_info
 
-type options = { program_options : Program_options.t
-	       ; imputed_line_length : int
-	       ; indentation_level : int
-	       ; parser_state : parser_state
-	       }
+type state = { program_options : Program_options.t
+	     ; imputed_line_length : int
+	     (* The number of indentations, not the number of spaces *)
+	     ; indentation_level : int
+	     (* This is the current line we aer reading, starting at 0 *)
+	     ; src_line_number : int
+	     (* This is current line number we are writing, starting at 0 *)
+	     ; dst_line_number : int
+	     ; parser_state : parser_state
+	     ; buffer : Buffer.t
+	     ; warnings : warning list
+	     }
 
 
-let format program_options out_chan code = raise (Failure "uhhh..")
+let default_state program_options buffer =
+  { program_options = program_options
+  ; imputed_line_length = 0
+  ; indentation_level = 0
+  ; src_line_number = 0
+  ; dst_line_number = 0
+  ; parser_state = Top_level
+  ; buffer = buffer
+  ; warnings = []
+  }
 
+let incr ?(step = 1) num = num + step
 
+let incr_src_line state =
+  { state with src_line_number = incr state.src_line_number }
+
+let incr_dst_line state =
+  Buffer.add_char state.buffer '\n';
+  { state with
+    dst_line_number = incr state.dst_line_number;
+    imputed_line_length = 0
+  }
+
+let fail state msg =
+  R.Failure { line_number = state.src_line_number
+	    ; msg = msg
+	    }
+
+let add_warning state msg =
+  { state with
+    warnings = { line_number = state.dst_line_number
+	       ; msg = msg
+	       }::state.warnings
+  }
+
+let is_line_too_long state line =
+  (String.length line
+   + state.indentation_level * state.program_options.Po.indent_spaces
+   > state.program_options.Po.max_line_length)
+
+let succeed state =
+  R.Success (Buffer.contents state.buffer, state.warnings)
+
+let rec format_top_level state = function
+  | Newline::xs ->
+    format_top_level (incr_dst_line (incr_src_line state)) xs
+  | (Comment text)::xs -> begin
+    Buffer.add_string state.buffer ("%" ^ text);
+    if is_line_too_long state text then
+      format_top_level
+	(add_warning state "Comment too long, please fix")
+	xs
+    else
+      format_top_level state xs
+  end
+  | (Keyword "-")::(Atom "module")::(Keyword "("
+  | [] -> succeed state
+  | _::xs -> format_top_level state xs
+
+let format_code program_options code =
+  (*
+   * Initiate the buffer at the number of tokens * 10, just
+   * a reasonable round number
+   *)
+  let buffer = Buffer.create (List.length code * 10) in
+  let state = default_state program_options buffer in
+  format_top_level state code
+
+let format program_options out_chan code =
+  match format_code program_options code with
+    | R.Success (formatted_code, warnings) -> begin
+      output_string out_chan formatted_code;
+      R.Success warnings
+    end
+    | R.Failure errors ->
+      R.Failure errors

src/formatter.mli

-val format : Program_options.t -> out_channel -> Token.t list -> unit
+type error = { line_number : int
+	     ; msg : string
+	     }
+
+type warning = error
+
+val format : Program_options.t -> out_channel -> Token.t list -> (warning list, error) Return.t

src/program_options.ml

 type t = { file_path : string option
 	 ; indent_spaces : int
+	 ; max_line_length : int
+	 (*
+	  * Maximum number of lines of code per
+	  * lines of comments.  Must be positive
+	  * integer, larger means more code allowed
+	  * per comments
+	  *)
+	 ; code_comment_ratio : int
 	 }
+type ('a, 'b) t = 
+  | Success of 'a
+  | Failure of 'b