1use std::path;
4
5mod arc_source_code;
6mod display;
7mod errors;
8mod try_from;
9
10pub(crate) use arc_source_code::ArcSourceCode;
11
12pub type LineNumber = usize;
14
15pub type CharOffset = usize;
17
18#[derive(Debug, serde::Deserialize, serde::Serialize)]
19pub struct SourceCode {
20 pub filename: path::PathBuf,
21 pub(crate) lines: LineNumber,
22 pub(crate) length_of_code_section: LineNumber,
23 pub(crate) length_of_csv_section: LineNumber,
24 pub(crate) code_section: Option<String>,
25 pub(crate) csv_section: String,
26 pub(crate) original: String,
27}
28
29impl SourceCode {
30 pub(crate) fn new<S, P>(input: S, filename: P) -> SourceCode
35 where
36 S: Into<String>,
37 P: Into<path::PathBuf>,
38 {
39 let str_input: String = input.into();
40
41 if let Some(p) = str_input
42 .lines()
43 .position(|l| regex::Regex::new(r"^\s*---\s*$").unwrap().is_match(l))
44 {
45 let lines: Vec<_> = str_input.lines().collect();
46 let csv_lines = &lines[(p + 1)..];
47 let code_lines = &lines[..p];
48
49 SourceCode {
50 filename: filename.into(),
51 lines: lines.len(),
52 length_of_code_section: code_lines.len() + 1,
54 length_of_csv_section: csv_lines.len(),
55 csv_section: csv_lines.join("\n"),
56 code_section: Some(code_lines.join("\n")),
57 original: str_input.clone(),
58 }
59 } else {
60 let csv_lines = str_input.lines().count();
61
62 SourceCode {
63 filename: filename.into(),
64 lines: csv_lines,
65 length_of_code_section: 0,
66 length_of_csv_section: csv_lines,
67 csv_section: str_input.clone(),
68 code_section: None,
69 original: str_input.clone(),
70 }
71 }
72 }
73
74 pub(crate) fn object_code_filename(&self) -> path::PathBuf {
75 let mut f = self.filename.clone();
76 f.set_extension("csvpo");
77 f
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use std::path;
85
86 fn build_source_code() -> SourceCode {
87 SourceCode {
88 filename: path::PathBuf::from("test.csvpp".to_string()),
89 lines: 25,
90 length_of_code_section: 10,
91 length_of_csv_section: 15,
92 code_section: Some("\n".repeat(10)),
93 csv_section: "foo,bar,baz".to_string(),
94 original: "\n\n\n\n\n\n\n\n\n\n---\nfoo,bar,baz".to_string(),
95 }
96 }
97
98 #[test]
99 fn object_code_filename() {
100 assert_eq!(
101 path::PathBuf::from("test.csvpo"),
102 build_source_code().object_code_filename()
103 );
104 }
105
106 #[test]
107 fn new() {
108 let source_code = SourceCode::new(
109 "foo := 2
110bar := 3
111---
112foo,bar,baz
113=foo",
114 "foo.csvpp",
115 );
116
117 assert_eq!(source_code.lines, 5);
118 assert_eq!(source_code.length_of_csv_section, 2);
119 assert_eq!(source_code.length_of_code_section, 3);
120 }
121
122 #[test]
123 fn new_no_scope() {
124 let source_code = SourceCode::new("foo,bar,baz", "foo.csvpp");
125
126 assert_eq!(source_code.lines, 1);
127 assert_eq!(source_code.length_of_csv_section, 1);
128 assert_eq!(source_code.length_of_code_section, 0);
129 assert_eq!(source_code.code_section, None);
130 assert_eq!(source_code.csv_section, "foo,bar,baz".to_string());
131 }
132}