1use crate::array::{Array, Data};
12use crate::verb::{Enclose, Power, Verb, WindowKind, RANK_INF};
13
14#[derive(Clone, Debug, PartialEq)]
16pub enum Ar {
17 Prim(String),
19 Noun(Array),
21 Derived(String, Vec<Ar>),
23 Train(Vec<Ar>),
25}
26
27fn chars(s: &str) -> Array {
28 Array::from_chars(s.chars().collect())
29}
30
31fn boxes(items: Vec<Array>) -> Array {
32 Array::new(vec![items.len()], Data::Box(items.into()))
33}
34
35fn pair(head: Array, body: Array) -> Array {
37 boxes(vec![head, body])
38}
39
40impl Ar {
41 pub fn to_array(&self) -> Array {
43 match self {
44 Ar::Prim(s) => chars(s),
45 Ar::Noun(a) => pair(chars("0"), a.clone()),
46 Ar::Derived(s, ops) => {
47 pair(chars(s), boxes(ops.iter().map(Ar::to_array).collect()))
48 }
49 Ar::Train(ops) => {
50 let tag = if ops.len() == 2 { "2" } else { "3" };
51 pair(chars(tag), boxes(ops.iter().map(Ar::to_array).collect()))
52 }
53 }
54 }
55
56 pub fn from_array(a: &Array) -> Option<Ar> {
59 if let Some(text) = text_of(a) {
60 return Some(Ar::Prim(text));
61 }
62 let items = a.as_boxes()?;
63 if a.rank() != 1 || items.len() != 2 {
64 return None;
65 }
66 let head = text_of(&items[0])?;
67 if head == "0" {
68 return Some(Ar::Noun(items[1].clone()));
69 }
70 let parts: Option<Vec<Ar>> = items[1].as_boxes()?.iter().map(Ar::from_array).collect();
71 let parts = parts?;
72 match head.as_str() {
73 "2" | "3" => Some(Ar::Train(parts)),
74 _ => Some(Ar::Derived(head, parts)),
75 }
76 }
77}
78
79pub fn text_of(a: &Array) -> Option<String> {
81 if a.rank() > 1 {
82 return None;
83 }
84 match a.row_major_data() {
85 Data::Char(v) => Some(v.as_slice().iter().collect()),
86 _ => None,
87 }
88}
89
90pub fn gerund_array(items: &[Ar]) -> Array {
92 boxes(items.iter().map(Ar::to_array).collect())
93}
94
95fn rank_noun(r: &[i64; 3]) -> Array {
97 let one = |v: i64| if v == RANK_INF { f64::INFINITY } else { v as f64 };
98 if r[0] == r[1] && r[1] == r[2] {
99 return Array::new(vec![], Data::F64(vec![one(r[0])].into()));
100 }
101 Array::from_f64(vec![one(r[0]), one(r[1]), one(r[2])])
102}
103
104fn power_noun(p: &Power) -> Option<Array> {
105 Some(match p {
106 Power::Times(n) => Array::scalar_i64(*n as i64),
107 Power::Converge => Array::scalar_f64(f64::INFINITY),
108 Power::Each(ns) => Array::from_i64(ns.iter().map(|&n| n as i64).collect()),
109 Power::ConvergeTrace => Array::boxed(Array::empty(crate::dtype::DType::I64)),
111 })
112}
113
114pub fn verb_ar(v: &Verb) -> Option<Ar> {
118 let der = |s: &str, ops: Vec<Ar>| Some(Ar::Derived(s.to_string(), ops));
119 match v {
120 Verb::Prim(p) if p.name == "b." => None,
123 Verb::Prim(p) => Some(Ar::Prim(p.name.to_string())),
124 Verb::Rank(inner, r) => rank_ar(inner, r),
125 Verb::Reduce(u) => der("/", vec![verb_ar(u)?]),
126 Verb::Windowed(u, WindowKind::Prefix) => der("\\", vec![verb_ar(u)?]),
127 Verb::Windowed(u, WindowKind::Suffix) => der("\\.", vec![verb_ar(u)?]),
128 Verb::Windowed(_, WindowKind::Scan) => None,
129 Verb::Commute(u) => der("~", vec![verb_ar(u)?]),
130 Verb::PowerN(u, p) => der("^:", vec![verb_ar(u)?, Ar::Noun(power_noun(p)?)]),
131 Verb::PowerV(u, w) => der("^:", vec![verb_ar(u)?, verb_ar(w)?]),
132 Verb::Fork(f, g, h) => Some(Ar::Train(vec![verb_ar(f)?, verb_ar(g)?, verb_ar(h)?])),
133 Verb::NounFork(n, g, h) => {
134 Some(Ar::Train(vec![Ar::Noun(n.clone()), verb_ar(g)?, verb_ar(h)?]))
135 }
136 Verb::Hook(f, g) => Some(Ar::Train(vec![verb_ar(f)?, verb_ar(g)?])),
137 Verb::Atop(f, g) => match under_ar(f, g, "&.:") {
138 Some(ar) => Some(ar),
139 None => der("@:", vec![verb_ar(f)?, verb_ar(g)?]),
140 },
141 Verb::Compose(f, g) => der("&:", vec![verb_ar(f)?, verb_ar(g)?]),
142 Verb::BondLeft(m, u) => der("&", vec![Ar::Noun(m.clone()), verb_ar(u)?]),
143 Verb::BondRight(u, n) => der("&", vec![verb_ar(u)?, Ar::Noun(n.clone())]),
144 Verb::Each(u, Enclose::Always) => {
145 der("&.", vec![verb_ar(u)?, Ar::Prim(">".to_string())])
146 }
147 Verb::Each(_, Enclose::ExceptSimpleScalar) => None,
148 Verb::Fit(u, n) => der("!.", vec![verb_ar(u)?, Ar::Noun(Array::scalar_f64(*n))]),
149 Verb::Amend(m) => der("}", vec![Ar::Noun(m.clone())]),
150 Verb::AmendVerb(u) => der("}", vec![verb_ar(u)?]),
151 Verb::Memo(u, _) => der("M.", vec![verb_ar(u)?]),
152 Verb::Level { u, level, spread } => der(
153 if *spread { "S:" } else { "L:" },
154 vec![verb_ar(u)?, Ar::Noun(Array::scalar_i64(*level))],
155 ),
156 Verb::Characteristics(u) => der("b.", vec![verb_ar(u)?]),
157 Verb::Key(u) => der("/.", vec![verb_ar(u)?]),
158 Verb::Cut(u, n) => der(";.", vec![verb_ar(u)?, Ar::Noun(Array::scalar_i64(*n))]),
159 Verb::Adverse(u, w) => der("::", vec![verb_ar(u)?, verb_ar(w)?]),
160 Verb::WithObverse(u, w) => der(":.", vec![verb_ar(u)?, verb_ar(w)?]),
161 Verb::Agenda(vs, w) => {
162 let items: Option<Vec<Ar>> = vs.iter().map(verb_ar).collect();
163 der("@.", vec![Ar::Noun(gerund_array(&items?)), verb_ar(w)?])
164 }
165 Verb::Evoke(vs, n) => {
166 let items: Option<Vec<Ar>> = vs.iter().map(verb_ar).collect();
167 der(
168 "`:",
169 vec![Ar::Noun(gerund_array(&items?)), Ar::Noun(Array::scalar_i64(*n))],
170 )
171 }
172 Verb::SelfRef => Some(Ar::Prim("$:".to_string())),
173 _ => None,
174 }
175}
176
177fn rank_ar(inner: &Verb, r: &[i64; 3]) -> Option<Ar> {
181 let der = |s: &str, ops: Vec<Ar>| Some(Ar::Derived(s.to_string(), ops));
182 if let Verb::Atop(f, g) = inner
185 && matches!(&**g, Verb::Compose(_, u) if *r == [u.ranks()[0]; 3])
186 && let Some(ar) = under_ar(f, g, "&.")
187 {
188 return Some(ar);
189 }
190 match inner {
191 Verb::Atop(f, g) if *r == g.ranks() => der("@", vec![verb_ar(f)?, verb_ar(g)?]),
192 Verb::Compose(f, g) if *r == [g.ranks()[0]; 3] => {
193 der("&", vec![verb_ar(f)?, verb_ar(g)?])
194 }
195 Verb::BondLeft(m, g) if *r == [g.ranks()[2]; 3] => {
196 der("&", vec![Ar::Noun(m.clone()), verb_ar(g)?])
197 }
198 Verb::BondRight(g, n) if *r == [g.ranks()[1]; 3] => {
199 der("&", vec![verb_ar(g)?, Ar::Noun(n.clone())])
200 }
201 _ => der("\"", vec![verb_ar(inner)?, Ar::Noun(rank_noun(r))]),
202 }
203}
204
205fn under_ar(f: &Verb, g: &Verb, spelling: &str) -> Option<Ar> {
209 let Verb::Compose(inner, under) = g else { return None };
210 let obverse = crate::frontend::j::obverse_of(under, crate::error::Span::new(0, 0)).ok()?;
211 if obverse.name() != f.name() {
212 return None;
213 }
214 Some(Ar::Derived(spelling.to_string(), vec![verb_ar(inner)?, verb_ar(under)?]))
215}