Pretty-printing with a comment string prefixing a box - ocaml

I am trying to generate a text file for use in another program. This program only has line-style comments. I want to pretty-print a comment that, whenever the line is broken, it is prefixed by //.
Here is what I have so far:
type elaborate_type = A | B
let elaborate_to_string = function
| A -> "OK, this is type A, but long"
| B -> "B"
let pp_elaborate chan v = Format.pp_print_string chan (elaborate_to_string v)
Format.printf "#[<hv2>{#,#[<hov>// Here is a long comment I want to break# // \
here, but also indent. It should also be the case that anything# // \
I put here (such as some complex printable term \"%a\") should# // \
only break if it has //, too).#]#,\
#[...#]\
#]#,}#."
pp_elaborate A
which gives the output
{
// Here is a long comment I want to break
// here, but also indent. It should also be the case that anything
// I put here (such as some complex printable term "OK, this is type A, but long") should
// only break if it has //, too).
...
}
Is there a way to do this without adding the //# to the end of each line I want to break?

A option to solving this issue is to update the newline function of the formatter to make it prints // right after the newline:
let add_double_slash_after_linebreak_and_before_indents fmt =
let fns = Format.pp_get_formatter_out_functions fmt () in
let out_newline () =
fns.out_newline ();
fns.out_string "//" 0 2
in
Format.pp_set_formatter_out_functions fmt { fns with out_newline}
let () =
let () =
add_double_slash_after_linebreak_and_before_indents Format.std_formatter
in
Format.printf "#[<v 2>This tests the formatting#,One line#,two line #]"
This tests the formatting
// One line
// two line val add_double_slash_after_linebreak_and_before_indents :
However, the double slashes // will appear at the start of the line independently of the indentation, if you prefer them to appear after the indentation, you can update the indentation function of the formatter instead:
let add_double_slash_after_linebreak_and_indents fmt =
let fns = Format.pp_get_formatter_out_functions fmt () in
let out_indent n =
fns.out_indent n;
fns.out_string "//" 0 2
in
Format.pp_set_formatter_out_functions fmt { fns with out_indent}
let () =
let () =
add_double_slash_after_linebreak_and_indents Format.std_formatter
in
Format.printf "#[<v 2>This tests the formatting#,One line#,two line #]"
This tests the formatting
//One line
//two line
Concerning your follow-up question, any \n in a string will mess up the formatting if there are printed with %s. You can avoid this issue by using pp_print_text which replaces and \n in the string by calls to pp_print_space and pp_force_line.

Related

If statements questions in OCaml

I am trying to write the following code in OCaml:
let a = 0
let b = 1
if a > b then
{
print_endline "a";
print_endline "a";
}
print_endline "b"
And then I encountered the following error:
File "[21]", line 4, characters 0-2:
4 | if a > b then
^^
Error: Syntax error
I have tried using the begin and end keywords.
If you're writing a program (rather than mucking about in a REPL), then there are only certain constructs which can exist at the top level of your program.
One of those is a binding. So the following is fine:
let a = 0
let b = 1
But a conditional expression (if/else) is not permitted. We can get around this by binding that expression to a pattern. Since print_endline will just return (), we can write:
let () =
...
Your use of { and } is incorrect in this situation, but you can grouped multiple expressions with ; and ( and ). Remember that ; is not a "statement terminator" but rather a separator.
let () =
if a > b then (
print_endline "a";
print_endline "a"
);
print_endline "b"
Note that if can only exist without a matching else if the entire expression returns unit. This meets that criteria.

What is this OCaml function returning?

As I understand it, OCaml doesn't require explicit return statements to yield a value from a function. The last line of the function is what returns something.
In that case, could someone please let me know what the following function foo is returning? It seems that it's returning a stream of data. Is it returning the lexer?
and foo ?(input = false) =
lexer
| 'x' _
-> let y = get_func lexbuf
get_text y
| ',' -> get_func lexbuf
| _ -> get_text lexbuf
I'm trying to edit the following function, bar, to return a data stream, as well, so that I can replace foo with bar in another function. However, it seems that bar has multiple lexers which is preventing this return. How can I rewrite bar to return a data stream in a similar way that foo appears to?
let bar cmd lexbuf =
let buff = Buffer.create 0 in
let quot plus =
lexer
| "<" -> if plus then Buffer.add_string b "<" quot plus lexbuf
and unquot plus =
lexer
| ">" -> if plus then Buffer.add_string b ">" unquot plus lexbuf
in
match unquot true lexbuf with
| e -> force_text cmd e
First, your code is probably using one of the old camlp4 syntax extension, you should precise that.
Second, foo is returning the same type of value as either get_text or get_funct. Without the code for those functions, it is not really possible to say more than that.
Third,
Buffer.add_string b ">" unquot plus lexbuf
is ill-typed. Are you missing parentheses:
Buffer.add_string b ">" (unquot plus lexbuf)
?

How to scan with ocamllex until end of file

I am trying to implement a parser that read regular expression. It ask the user to enter a valid input of string/integers/float. If is valid and the user press ctrl^d, then print the number. Otherwise shows an error. But the problem in the following code does not stop when I press ctrl^D. How to implement eof token and print the input ?
test.mll :
{ type result = Int of int | Float of float | String of string }
let digit = ['0'-'9']
let digits = digit +
let lower_case = ['a'-'z']
let upper_case = ['A'-'Z']
let letter = upper_case | lower_case
let letters = letter +
rule main = parse
(digits)'.'digits as f { Float (float_of_string f) }
| digits as n { Int (int_of_string n) }
| letters as s { String s}
| _ { main lexbuf }
{ let newlexbuf = (Lexing.from_channel stdin) in
let result = main newlexbuf in
print_endline result }
I'd say the main problem is that each call to main produces one token, and there's only one call to main in your code. So it will process just one token.
You need to have some kind of iteration that calls main repeatedly.
There is a special pattern eof in OCamllex that matches the end of the input file. You can use this to return a special value that stops the iteration.
As a side comment, you can't call print_endline with a result as its parameter. Its parameter must be a string. You will need to write your own function for printing the results.
Update
To get an iteration, change your code to something like this:
{
let newlexbuf = Lexing.from_channel stdin in
let rec loop () =
match main newlexbuf with
| Int i -> iprint i; loop ()
| Float f -> fprint f; loop ()
| String s -> sprint s; loop ()
| Endfile -> ()
in
loop ()
}
Then add a rule something like this to your patterns:
| eof { Endfile }
Then add Endfile as an element of your type.
A assume this is homework. So make sure you see how the iteration is working. Aside from the details of ocamllex, that's something you want to master (apologies for unsolicited advice).

OCAML Taking multiple arguments from stdin and operating on them one by one

I have written an interpreter using ocamllex and ocamlyacc, the lexer and the parser work correctly but currently they only parse the last .txt argument it receives as oppose to all of them in turn. For example, ./interpret one.txt two.txt three.txt only parses three.txt as oppose to parsing one.txt and then two.txt and then three.txt which is what I want. So for example the parse results are as follows:
one.txt -> "1"
two.txt -> "2"
three.txt -> "3"
On calling ./interpret one.txt two.txt three.txt the current output is: 3 but I want it to be 123
Here is my main class which deals with the stdin and stdout
open Lexer
open Parser
open Arg
open Printf
let toParse c =
try let lexbuf = Lexing.from_channel c in
parser_main lexer_main lexbuf
with Parsing.Parse_error -> failwith "Parse failure!" ;;
let argument = ref stdin in
let prog p = argument := open_in p in
let usage = "./interpreter FILE" in
parse [] prog usage ;
let parsed = toParse !argument in
let result = eval parsed in
let _ = parsed in
flush stdout;
Thanks for your time
There's not really enough code here to be able to help.
If I assume that the output is written by eval, then I see only one call to eval. But there's nothing here that deals with filenames from the command line, so it's hard to say more.
If you are planning to read input from files, then there's no reason to be using stdin for anything as far as I can tell.
(I know this is a very minor point, but this code doesn't constitute a class. Other languages use classes for everything, but this is a module.)
Update
Here's a module that works something like the Unix cat command; it writes out the contents of all the files from the command line one after the next.
let cat () =
for i = 1 to Array.length Sys.argv - 1 do
let ic = open_in Sys.argv.(i) in
let rec loop () =
match input_line ic with
| line -> output_string stdout (line ^ "\n"); loop ()
| exception End_of_file -> ()
in
loop ();
close_in ic
done
let () = cat ()
Here's how it looks when you compile and run it.
$ ocamlc -o mycat mycat.ml
$ echo test line 1 > file1
$ echo test line 2 > file2
$ ./mycat file1 file2
test line 1
test line 2

writing main() to call a function

I have an OCaml function that converts a string to an array. What is the canonical way of writing a "main" function to call this and print the array.
let createArray pattern patArray =
(* some unimportant way of setting all the elements in the array patArray
based on the string pattern *)
let main () =
let pattern = "Pattern" in
let patArray = Array.create (String.length pattern) 0 in
let res = createArray pattern patArray in
Array.iter ~f:(printf "%d ") patArray;; <------------------
main ()
1) In the above, if I leave out the ';;' , it does not work. What is the significance of that?
2) Instead of using a dummy binding "res" , can I somehow just write two statements to be executed sequentially , like so:
createArray pattern patArray
Array.iter ~f:(printf "%d ") patArray
Without the ;;, the parser cannot know that the main () call following that line is supposed to be a stand-alone expression (whitespace is not significant here).
You can use the following idiom instead:
let main () = ...
let () = main ()
The let () = expr idiom will evaluate an expression of type unit at that point. The initial let informs the parser that a new top-level let construct begins. Using ;; is an alternative way to tell the parser about the end of a top-level construct, but is primarily intended for interactive use.
In order to evaluate two expressions sequentially, separate them with a semicolon (use parentheses or begin ... end if you're unsure about precedence rules). For example:
let patArray = Array.create (String.length pattern) 0 in
createArray pattern patArray;
Array.iter ~f:(printf "%d ") patArray
Or, using begin and end to make precedence clearer:
let patArray = Array.create (String.length pattern) 0 in begin
createArray pattern patArray;
Array.iter ~f:(printf "%d ") patArray
end
Without the ;, the parser would not know whether Array.iter on the next line is supposed to an additional argument to the createArray call.