Skip to content

Commit fe41911

Browse files
authored
Merge branch 'fram-lang:master' into master
2 parents dae76bc + ac60ba6 commit fe41911

File tree

17 files changed

+344
-141
lines changed

17 files changed

+344
-141
lines changed

.github/workflows/Test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ jobs:
1616
- run: opam exec -- dune build
1717
- run: opam exec -- dune install
1818
- run: eval $(opam env) && ./test.sh dbl ./test/test_suite
19-
19+

dune-project

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33

44
(generate_opam_files true)
55

6+
(source (github fram-lang/dbl))
7+
(license MIT)
8+
69
(package
710
(name dbl)
811
(synopsis "Interpreter of Fram: a language with algebraic effects and powerful named parameters")
9-
(description ""))
12+
(description "")
13+
(depends
14+
(dune (>= 3.11))))

src/DblConfig.ml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,15 @@ let local_mod_prefix = "Main"
2020

2121
let lib_search_dirs : string list ref = ref [ ]
2222
let local_search_dirs : string list ref = ref [ ]
23+
24+
let print_colors_auto () =
25+
Unix.isatty Unix.stdout
26+
27+
let display_colors = ref (print_colors_auto ())
28+
29+
let print_colors_of_string = function
30+
| "always" -> display_colors := true
31+
| "never" -> display_colors := false
32+
| "auto" -> display_colors := print_colors_auto ()
33+
| _ -> assert false
34+

src/DblParser/Desugar.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ let rec tr_pattern ~public (p : Raw.expr) =
316316
let ps = List.map (tr_pattern ~public) ps in
317317
begin match flds with
318318
| [ { data = FldModule name; _ } ] ->
319-
make (PCtor(cpath, CNModule name, ps))
319+
make (PCtor(cpath, CNModule(public, name), ps))
320320
| _ ->
321321
let (targs, iargs) = map_inst_like (tr_named_pattern ~public) flds in
322322
make (PCtor(cpath, CNParams(targs, iargs), ps))

src/DblParser/Main.ml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,14 @@ let rec repl_seq imported () =
2222

2323
and repl_seq_main imported () =
2424
flush stderr;
25+
Buffer.clear InterpLib.Error.repl_input;
26+
let fn buf n =
27+
let res = input stdin buf 0 n in
28+
Buffer.add_subbytes InterpLib.Error.repl_input buf 0 res;
29+
res
30+
in
2531
Printf.printf "> %!";
26-
let lexbuf = Lexing.from_channel stdin in
32+
let lexbuf = Lexing.from_function fn in
2733
lexbuf.Lexing.lex_curr_p <-
2834
{ lexbuf.Lexing.lex_curr_p with
2935
Lexing.pos_fname = "<stdin>"
@@ -38,8 +44,8 @@ and repl_seq_main imported () =
3844
Seq.Cons([def], repl_seq imported)
3945

4046
| Raw.REPL_Defs defs ->
41-
let defs = Desugar.tr_defs defs in
42-
Seq.Cons(defs, repl_seq imported)
47+
let defs = Desugar.tr_defs defs in
48+
Seq.Cons(defs, repl_seq imported)
4349

4450
| Raw.REPL_Import import ->
4551
let imported, defs = Import.import_one imported import in

src/InterpLib/Error.ml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,35 @@ type error_class =
1414

1515
let err_counter = ref 0
1616

17+
let repl_input = Buffer.create 512
18+
1719
let incr_error_counter () =
1820
err_counter := !err_counter + 1
1921

22+
let color_printer_generator color s =
23+
if not !DblConfig.display_colors
24+
then s
25+
else TextRangePrinting.color_string color s
26+
2027
let report ?pos ~cls msg =
21-
let name =
28+
let module Color = TextRangePrinting in
29+
let name, color =
2230
match cls with
2331
| FatalError ->
2432
incr_error_counter ();
25-
"fatal error"
33+
"fatal error", Color.Red
2634
| Error ->
2735
incr_error_counter ();
28-
"error"
29-
| Warning -> "warning"
30-
| Note -> "note"
36+
"error", Color.Red
37+
| Warning -> "warning", Color.Yellow
38+
| Note -> "note", Color.Teal
3139
in
32-
match pos, Option.bind pos Position.get_text_range with
40+
let name = Color.color_string color name in
41+
let text_range = Option.bind pos
42+
(TextRangePrinting.get_text_range
43+
~repl_input:(Buffer.contents repl_input)
44+
~color) in
45+
match pos, text_range with
3346
| Some pos, None ->
3447
Printf.eprintf "%s: %s: %s\n"
3548
(Position.to_string pos) name msg

src/InterpLib/Error.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ val wrap_repl_cont : (unit -> 'a) -> unit -> 'a
3535

3636
(** Reset state of reported errors. Used in REPL in case of an error. *)
3737
val reset : unit -> unit
38+
39+
(** A buffer that contains last REPL input. *)
40+
val repl_input : Buffer.t

src/InterpLib/TextRangePrinting.ml

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
(* This file is part of DBL, released under MIT license.
2+
* See LICENSE for details.
3+
*)
4+
5+
(** Pretty printing of text range from Position.t *)
6+
open Position
7+
8+
(* ========================================================================= *)
9+
(** Options for underlining specified region *)
10+
type underline_options =
11+
| NoUnderline
12+
(** Disable underlining *)
13+
14+
| UnderlineBegining
15+
(** Point to only beginning of region *)
16+
17+
| UnderlineIfOneLine
18+
(** Underline whole region, but only if specifies only one line *)
19+
20+
| UnderlineAlways
21+
(** Underline whole region *)
22+
23+
type options = {
24+
context : int;
25+
(** how many lines before region is to be printed *)
26+
27+
underline : t -> underline_options;
28+
(** function that depending on region will select underlining option *)
29+
30+
add_line_numbers : bool;
31+
(** should line numbers be added *)
32+
}
33+
34+
let default_options = {
35+
context = 2;
36+
underline = (fun _ -> UnderlineIfOneLine);
37+
add_line_numbers = true;
38+
}
39+
40+
(* ========================================================================= *)
41+
(** Printing to terminal with colors *)
42+
43+
let keyword_color = "\027[1;34m"
44+
45+
type printing_color =
46+
| Red
47+
| Teal
48+
| Yellow
49+
| Black
50+
| Green
51+
| Blue
52+
| Magenta
53+
| Cyan
54+
| White
55+
| Default
56+
57+
let color_to_string = function
58+
| Black -> "\027[30m"
59+
| Red -> "\027[31m"
60+
| Green -> "\027[32m"
61+
| Yellow -> "\027[33m"
62+
| Blue -> "\027[34m"
63+
| Magenta -> "\027[35m"
64+
| Teal -> "\027[36m"
65+
| Cyan -> "\027[36m"
66+
| White -> "\027[37m"
67+
| Default -> "\027[0m"
68+
69+
let bold_code_string = "\027[1m"
70+
let dim_code_string = "\027[2m"
71+
let italic_code_string = "\027[3m"
72+
let underline_code_string = "\027[4m"
73+
let blink_code_string = "\027[5m"
74+
let rapid_blink_code_string = "\027[6m"
75+
let reverse_code_string = "\027[7m"
76+
let hidden_code_string = "\027[8m"
77+
78+
let reset_string = color_to_string Default
79+
80+
let color_string color s =
81+
if not !DblConfig.display_colors
82+
then s
83+
else color_to_string color ^ s ^ reset_string
84+
85+
let bolden_string s =
86+
if not !DblConfig.display_colors
87+
then s
88+
else bold_code_string ^ s ^ reset_string
89+
90+
let underline_string s =
91+
if not !DblConfig.display_colors
92+
then s
93+
else underline_code_string ^ s ^ reset_string
94+
95+
(* ========================================================================= *)
96+
(** Underlining *)
97+
98+
let find_tabs line =
99+
String.fold_left (fun (i, acc) c ->
100+
if c = '\t' then (i+1, i::acc) else (i+1, acc)) (0, []) line
101+
|> snd
102+
103+
let generate_underline ~color_printer start_cnum len tabs =
104+
if len <= 0 then "" else
105+
let underline = String.make len '^' |> color_printer in
106+
let padding = String.make (start_cnum - 1) ' ' in
107+
let f i _ =
108+
if List.mem i tabs
109+
then '\t'
110+
else ' '
111+
in String.mapi f padding ^ underline
112+
113+
let add_underline ~options ~pos ~color_printer (i, line) =
114+
match options.underline pos, i with
115+
| NoUnderline, _ -> Seq.return (i, line)
116+
| (UnderlineIfOneLine | UnderlineAlways), Some j
117+
when pos.pos_start_line = pos.pos_end_line
118+
&& pos.pos_start_line = j ->
119+
let underline = generate_underline ~color_printer
120+
(start_column pos) pos.pos_length (find_tabs line) in
121+
Seq.cons (i, line) (Seq.return (None, underline))
122+
| UnderlineIfOneLine, _ -> Seq.return (i, line)
123+
| UnderlineBegining, Some j
124+
when pos.pos_start_line = j ->
125+
let underline = generate_underline ~color_printer
126+
(start_column pos) 1 (find_tabs line) in
127+
Seq.cons (i, line) (Seq.return (None, underline))
128+
| UnderlineBegining, _ -> Seq.return (i, line)
129+
| UnderlineAlways, Some j
130+
when j = pos.pos_start_line ->
131+
let underline = generate_underline ~color_printer
132+
(start_column pos)
133+
(String.length line - start_column pos)
134+
(find_tabs line) in
135+
Seq.cons (i, line) (Seq.return (None, underline))
136+
| UnderlineAlways, Some j
137+
when j = pos.pos_end_line ->
138+
let underline = generate_underline ~color_printer
139+
0 (end_column pos) (find_tabs line) in
140+
Seq.cons (i, line) (Seq.return (None, underline))
141+
| UnderlineAlways, Some j
142+
when j > pos.pos_start_line && j < pos.pos_end_line ->
143+
let underline = generate_underline ~color_printer
144+
0 (String.length line) (find_tabs line) in
145+
Seq.cons (i, line) (Seq.return (None, underline))
146+
| UnderlineAlways, _ -> Seq.return (i, line)
147+
148+
(* ========================================================================= *)
149+
(** Printing code *)
150+
151+
let add_line_number ~options ~pos ~color_printer end_line =
152+
let align_to = Float.of_int end_line
153+
|> Float.log10
154+
|> Float.to_int
155+
in
156+
fun (i, line) ->
157+
if not options.add_line_numbers then
158+
String.make (align_to + 3) ' ' ^ "| " ^ line
159+
else
160+
match i with
161+
| None -> String.make (align_to + 3) ' ' ^ "| " ^ line
162+
| Some i ->
163+
let separator = if i >= pos.pos_start_line && i <= pos.pos_end_line
164+
then color_printer "|>" else "| " in
165+
Printf.sprintf " %*d %s%s" (align_to + 1) i separator line
166+
167+
let process ~pos ~options ~color_printer seq =
168+
let to_drop = pos.pos_start_line - 1 - options.context in
169+
let to_take =
170+
pos.pos_end_line - pos.pos_start_line + 1 +
171+
options.context - (Int.min 0 to_drop) in
172+
let lines = seq
173+
|> Seq.zip (Seq.ints 1 |> Seq.map Option.some)
174+
|> Seq.drop (Int.max to_drop 0)
175+
|> Seq.take to_take
176+
|> Seq.flat_map (add_underline ~options ~pos ~color_printer)
177+
|> Seq.map (add_line_number pos.pos_end_line ~options ~pos ~color_printer)
178+
in
179+
String.concat "\n" @@ List.of_seq lines
180+
181+
let get_text_from_repl ~options ~repl_input ~color_printer pos =
182+
let lines = String.split_on_char '\n' repl_input in
183+
let options = { options with add_line_numbers=false } in
184+
let file_chunk = process ~pos ~options
185+
~color_printer (List.to_seq lines) in
186+
Some file_chunk
187+
188+
let get_text_from_file ~options ~color_printer pos =
189+
if Fun.negate Sys.file_exists pos.pos_fname then None else
190+
let get_line fd () = In_channel.input_line fd in
191+
let process_file fd = process ~pos ~options ~color_printer
192+
(Seq.of_dispenser (get_line fd)) in
193+
let file_chunk = In_channel.with_open_text pos.pos_fname process_file in
194+
let pp_file_name = " -> " ^ pos.pos_fname ^ "\n" in
195+
Some (pp_file_name ^ file_chunk)
196+
197+
let get_text_range ?(options=default_options) ~repl_input ~color (pos : t) =
198+
let color_printer = color_string color in
199+
if pos.pos_fname = "<stdin>" && repl_input <> "" then
200+
get_text_from_repl ~options ~repl_input ~color_printer pos
201+
else
202+
get_text_from_file ~options ~color_printer pos
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
(* This file is part of DBL, released under MIT license.
2+
* See LICENSE for details.
3+
*)
4+
5+
(* ========================================================================= *)
6+
(** Printing to terminal with colors *)
7+
type printing_color =
8+
| Red
9+
| Teal
10+
| Yellow
11+
| Black
12+
| Green
13+
| Blue
14+
| Magenta
15+
| Cyan
16+
| White
17+
| Default
18+
19+
val color_string : printing_color -> string -> string
20+
val bolden_string : string -> string
21+
val underline_string : string -> string
22+
23+
(* ========================================================================= *)
24+
(** Options for underlining specified region *)
25+
type underline_options =
26+
| NoUnderline
27+
(** Disable underlining *)
28+
29+
| UnderlineBegining
30+
(** Point to only beginning of region *)
31+
32+
| UnderlineIfOneLine
33+
(** Underline whole region, but only if specifies only one line *)
34+
35+
| UnderlineAlways
36+
(** Underline whole region *)
37+
38+
type options = {
39+
context : int;
40+
(** how many lines before and after region is to be printed *)
41+
42+
underline : Position.t -> underline_options;
43+
(** function that depending on region will select underlining option *)
44+
45+
add_line_numbers : bool;
46+
(** should line numbers be added *)
47+
}
48+
49+
val default_options : options
50+
51+
val get_text_range : ?options:options -> repl_input:string
52+
-> color:printing_color -> Position.t -> string option

src/InterpLib/dune

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
(library
22
(name interpLib)
3-
(libraries utils))
3+
(libraries utils dblConfig str))

0 commit comments

Comments
 (0)