satysfi_parser/types/
structure.rs

1//! saty ファイル、satyh ファイルの大まかな構造を格納したデータ構造。
2
3use crate::{Cst, LineCol, Rule, Span};
4use anyhow::{anyhow, Result};
5use itertools::Itertools;
6
7trait FromCst: Sized {
8    fn from_cst(cst: &Cst) -> Result<Self>;
9}
10
11/// CstText と似ているが、こちらは構文要素が構造体で分かれている。
12#[derive(Debug)]
13pub struct ProgramText {
14    pub structure: Result<Program>,
15    pub cst: Cst,
16    pub lines: Vec<usize>,
17    pub text: String,
18}
19
20impl ProgramText {
21    pub fn parse(text: &str) -> std::result::Result<Self, (LineCol, Vec<&'static str>)> {
22        match crate::grammar::program(text) {
23            Ok(cst) => {
24                let mut lines = vec![0usize];
25                lines.extend(text.match_indices('\n').map(|(p, _)| p + 1));
26                let structure = Program::from_cst(&cst);
27                Ok(ProgramText {
28                    text: text.to_owned(),
29                    cst,
30                    lines,
31                    structure,
32                })
33            }
34            Err(e) => {
35                let peg::str::LineCol { line, column, .. } = e.location;
36                let lc = LineCol {
37                    line: line - 1,
38                    column: column - 1,
39                }; // 0-indexed に変換
40                let expected: Vec<_> = e.expected.tokens().collect();
41                Err((lc, expected))
42            }
43        }
44    }
45
46    /// self.cst の子要素である Cst について、その要素に相当する text を取得する。
47    pub fn get_text_from_span(&self, span: Span) -> &str {
48        let text = self.text.as_str();
49        let Span { start, end } = span;
50        &text[start..end]
51    }
52
53    /// self.cst の子要素である Cst について、その要素に相当する text を取得する。
54    pub fn get_text(&self, cst: &Cst) -> &str {
55        let text = self.text.as_str();
56        let Span { start, end } = cst.span;
57        &text[start..end]
58    }
59
60    /// 与えられた position の line 及び col を出力する。
61    pub fn get_line_col(&self, pos: usize) -> Option<LineCol> {
62        if pos > self.text.len() {
63            return None;
64        }
65        let line = match self.lines.binary_search(&pos) {
66            Ok(i) => i,
67            Err(i) => i - 1,
68        };
69        let column = pos - self.lines[line];
70        Some(LineCol { line, column })
71    }
72
73    /// 与えられた line 及び col の position を出力する。
74    pub fn from_line_col(&self, line: usize, column: usize) -> Option<usize> {
75        let idxline = self.lines.get(line)?;
76        let max_idx = match self.lines.get(line + 1) {
77            Some(idx) => *idx,
78            None => self.text.len(),
79        };
80        if (*idxline + column) < max_idx {
81            Some(*idxline + column)
82        } else {
83            None
84        }
85    }
86
87    /// Cst を pritty 表示。
88    pub fn pritty_cst(&self, cst: &Cst) -> String {
89        let mut s = String::new();
90        s.push_str(&format!("[{:?}]", cst.rule));
91
92        // 長すぎないものだけテキストを表示
93        let Span { start, end } = cst.span;
94        let slice = &self.text[start..end];
95        if !slice.contains('\n') && slice.len() < 80 {
96            s.push_str(&format!(": \"{}\"", slice));
97        } else {
98            let LineCol {
99                line: start_line,
100                column: start_column,
101            } = self.get_line_col(start).unwrap();
102            let LineCol {
103                line: end_line,
104                column: end_column,
105            } = self.get_line_col(end).unwrap();
106            s.push_str(&format!(
107                " (L{}-C{} .. L{}-C{})",
108                start_line + 1,
109                start_column + 1,
110                end_line + 1,
111                end_column + 1
112            ));
113        }
114        s
115    }
116
117    /// 与えられた場所がコメント内かどうか判定する。
118    pub fn is_comment(&self, pos: usize) -> bool {
119        let dig = self.cst.dig(pos);
120        let cst = dig.get(0);
121        if cst.is_none() {
122            return false;
123        }
124        let cst = cst.unwrap();
125        // cst: その pos を含む最小の cst
126        // span: pos を含む終端要素
127        let span = cst
128            .get_terminal_spans()
129            .into_iter()
130            .find(|span| span.includes(pos));
131        if span.is_none() {
132            // span が見つからないことは無いと思うんだけど
133            return false;
134        }
135        let span = span.unwrap();
136
137        // TODO: まあまあアドホックなのでなんとかしたい
138        let text = self.get_text_from_span(span);
139        let char_indices = text.char_indices().map(|(idx, _)| idx).collect_vec();
140        let pos_char = char_indices
141            .binary_search(&(pos - span.start))
142            .unwrap_or_else(|x| x);
143        for c in text.chars().take(pos_char).collect_vec().into_iter().rev() {
144            match c {
145                // 改行が見つかったらそこで探索打ち切り。コメントでないこと確定
146                '\n' => return false,
147                // コメント文字が見つかったらコメント確定。
148                '%' => return true,
149                _ => continue,
150            }
151        }
152        // 改行もコメント文字も何も見つからなかったらコメントでないこと確定。
153        false
154    }
155}
156
157#[derive(Debug, PartialEq, Eq)]
158pub enum Program {
159    Saty {
160        header_stage: Option<Cst>,
161        header: Vec<Header>,
162        preamble: Vec<Statement>,
163        expr: Cst,
164    },
165    Satyh {
166        header_stage: Option<Cst>,
167        header: Vec<Header>,
168        preamble: Vec<Statement>,
169    },
170}
171
172impl FromCst for Program {
173    fn from_cst(cst: &Cst) -> Result<Self> {
174        let mut inner = cst.inner.iter().peekable();
175        let header_stage = if inner
176            .peek()
177            .ok_or(anyhow!("expected stage or headers."))?
178            .rule
179            == Rule::stage
180        {
181            let stage = inner.next().unwrap();
182            Some(stage.clone())
183        } else {
184            None
185        };
186        let header = {
187            let headers = inner.next().unwrap();
188            let v: Result<Vec<_>> = headers
189                .inner
190                .iter()
191                .map(|cst| Header::from_cst(cst))
192                .collect();
193            v?
194        };
195
196        match cst.rule {
197            Rule::program_saty => {
198                let preamble = if inner
199                    .peek()
200                    .ok_or(anyhow!("expected preamble or expr"))?
201                    .rule
202                    == Rule::preamble
203                {
204                    let preamble = inner.next().unwrap();
205                    let v: Result<Vec<_>> = preamble
206                        .inner
207                        .iter()
208                        .map(|cst| Statement::from_cst(cst))
209                        .collect();
210                    v?
211                } else {
212                    vec![]
213                };
214                let expr = inner.next().ok_or(anyhow!("expected expr"))?.clone();
215                Ok(Program::Saty {
216                    header_stage,
217                    header,
218                    preamble,
219                    expr,
220                })
221            }
222            Rule::program_satyh => {
223                let preamble = {
224                    let preamble = inner.next().ok_or(anyhow!("expected preamble"))?;
225                    let v: Result<Vec<_>> = preamble
226                        .inner
227                        .iter()
228                        .map(|cst| Statement::from_cst(cst))
229                        .collect();
230                    v?
231                };
232                Ok(Program::Satyh {
233                    header_stage,
234                    header,
235                    preamble,
236                })
237            }
238            _ => unreachable!(),
239        }
240    }
241}
242
243#[derive(Debug, PartialEq, Eq)]
244pub struct Header {
245    pub name: Cst,
246    pub kind: HeaderKind,
247}
248
249impl FromCst for Header {
250    fn from_cst(cst: &Cst) -> Result<Self> {
251        let name = cst.inner.get(0).ok_or(anyhow!("expected pkgname"))?.clone();
252        let kind = match cst.rule {
253            Rule::header_require => HeaderKind::Require,
254            Rule::header_import => HeaderKind::Import,
255            _ => unreachable!(),
256        };
257        Ok(Header { name, kind })
258    }
259}
260
261#[derive(Debug, PartialEq, Eq)]
262pub enum HeaderKind {
263    Require,
264    Import,
265}
266
267#[derive(Debug, PartialEq, Eq)]
268pub enum Statement {
269    Let {
270        pat: Cst,
271        type_annot: Option<Cst>,
272        args: Vec<Cst>,
273        expr: Cst,
274    },
275    LetRec(Vec<LetRecInner>),
276    LetInline {
277        var_context: Option<Cst>,
278        cmd: Cst,
279        args: Vec<Cst>,
280        expr: Cst,
281    },
282    LetBlock {
283        var_context: Option<Cst>,
284        cmd: Cst,
285        args: Vec<Cst>,
286        expr: Cst,
287    },
288    LetMath {
289        cmd: Cst,
290        args: Vec<Cst>,
291        expr: Cst,
292    },
293    LetMutable {
294        var: Cst,
295        expr: Cst,
296    },
297    Type(Vec<TypeInner>),
298    Module {
299        name: Cst,
300        signature: Vec<Signature>,
301        statements: Vec<Statement>,
302    },
303    Open(Cst),
304}
305
306impl FromCst for Statement {
307    fn from_cst(cst: &Cst) -> Result<Self> {
308        let stmt = match cst.rule {
309            Rule::let_stmt => {
310                let mut inner = cst.inner.iter().peekable();
311                let pat = inner.next().ok_or(anyhow!("expected pattern"))?.clone();
312                let type_annot = if inner
313                    .peek()
314                    .ok_or(anyhow!("expected type_expr or arg"))?
315                    .rule
316                    == Rule::type_expr
317                {
318                    Some(inner.next().unwrap().clone())
319                } else {
320                    None
321                };
322                let mut args = vec![];
323                while inner.peek().ok_or(anyhow!("expected expr"))?.rule == Rule::arg {
324                    let arg = inner.next().unwrap().clone();
325                    args.push(arg);
326                }
327                let expr = inner.next().unwrap().clone();
328                Statement::Let {
329                    pat,
330                    type_annot,
331                    args,
332                    expr,
333                }
334            }
335
336            Rule::let_rec_stmt => {
337                let let_rec_inner: Result<Vec<_>> = cst
338                    .inner
339                    .iter()
340                    .map(|rec_inner| LetRecInner::from_cst(rec_inner))
341                    .collect();
342                Statement::LetRec(let_rec_inner?)
343            }
344
345            Rule::let_inline_stmt_ctx => {
346                let mut inner = cst.inner.iter().peekable();
347                let var_context = Some(inner.next().ok_or(anyhow!("expected context"))?.clone());
348                let cmd = inner
349                    .next()
350                    .ok_or(anyhow!("expected command name"))?
351                    .clone();
352                let mut args = vec![];
353                while inner.peek().ok_or(anyhow!("expected expr"))?.rule == Rule::pattern {
354                    let arg = inner.next().unwrap().clone();
355                    args.push(arg);
356                }
357                let expr = inner.next().unwrap().clone();
358                Statement::LetInline {
359                    var_context,
360                    cmd,
361                    args,
362                    expr,
363                }
364            }
365            Rule::let_inline_stmt_noctx => {
366                let mut inner = cst.inner.iter().peekable();
367                let var_context = None;
368                let cmd = inner
369                    .next()
370                    .ok_or(anyhow!("expected command name"))?
371                    .clone();
372                let mut args = vec![];
373                while inner.peek().ok_or(anyhow!("expected expr"))?.rule == Rule::arg {
374                    let arg = inner.next().unwrap().clone();
375                    args.push(arg);
376                }
377                let expr = inner.next().unwrap().clone();
378                Statement::LetInline {
379                    var_context,
380                    cmd,
381                    args,
382                    expr,
383                }
384            }
385
386            Rule::let_block_stmt_ctx => {
387                let mut inner = cst.inner.iter().peekable();
388                let var_context = Some(inner.next().ok_or(anyhow!("expected context"))?.clone());
389                let cmd = inner
390                    .next()
391                    .ok_or(anyhow!("expected command name"))?
392                    .clone();
393                let mut args = vec![];
394                while inner.peek().ok_or(anyhow!("expected expr"))?.rule == Rule::pattern {
395                    let arg = inner.next().unwrap().clone();
396                    args.push(arg);
397                }
398                let expr = inner.next().unwrap().clone();
399                Statement::LetBlock {
400                    var_context,
401                    cmd,
402                    args,
403                    expr,
404                }
405            }
406            Rule::let_block_stmt_noctx => {
407                let mut inner = cst.inner.iter().peekable();
408                let var_context = None;
409                let cmd = inner
410                    .next()
411                    .ok_or(anyhow!("expected command name"))?
412                    .clone();
413                let mut args = vec![];
414                while inner.peek().ok_or(anyhow!("expected expr"))?.rule == Rule::arg {
415                    let arg = inner.next().unwrap().clone();
416                    args.push(arg);
417                }
418                let expr = inner.next().unwrap().clone();
419                Statement::LetBlock {
420                    var_context,
421                    cmd,
422                    args,
423                    expr,
424                }
425            }
426
427            Rule::let_math_stmt => {
428                let mut inner = cst.inner.iter().peekable();
429                let cmd = inner
430                    .next()
431                    .ok_or(anyhow!("expected command name"))?
432                    .clone();
433                let mut args = vec![];
434                while inner.peek().ok_or(anyhow!("expected expr"))?.rule == Rule::arg {
435                    let arg = inner.next().unwrap().clone();
436                    args.push(arg);
437                }
438                let expr = inner.next().unwrap().clone();
439                Statement::LetMath { cmd, args, expr }
440            }
441
442            Rule::let_mutable_stmt => {
443                let var = cst
444                    .inner
445                    .get(0)
446                    .ok_or(anyhow!("expected var name"))?
447                    .clone();
448                let expr = cst.inner.get(1).ok_or(anyhow!("expected expr"))?.clone();
449                Statement::LetMutable { var, expr }
450            }
451
452            Rule::type_stmt => {
453                let type_inners: Result<Vec<_>> = cst
454                    .inner
455                    .iter()
456                    .map(|type_inner| TypeInner::from_cst(type_inner))
457                    .collect();
458                Statement::Type(type_inners?)
459            }
460
461            Rule::module_stmt => {
462                let name = cst.inner.get(0).ok_or(anyhow!("expected name"))?.clone();
463                let sig_stmt = cst.inner.get(1).ok_or(anyhow!("expected sig_stmt"))?;
464                let struct_stmt = cst.inner.get(2).ok_or(anyhow!("expected struct_stmt"))?;
465                let signature: Result<Vec<_>> = sig_stmt
466                    .inner
467                    .iter()
468                    .map(|sig_inner| Signature::from_cst(sig_inner))
469                    .collect();
470                let signature = signature?;
471                let statements: Result<Vec<_>> = struct_stmt
472                    .inner
473                    .iter()
474                    .map(|stmt| Statement::from_cst(stmt))
475                    .collect();
476                let statements = statements?;
477                Statement::Module {
478                    name,
479                    signature,
480                    statements,
481                }
482            }
483
484            Rule::open_stmt => Statement::Open(
485                cst.inner
486                    .get(0)
487                    .ok_or(anyhow!("expected module name"))?
488                    .clone(),
489            ),
490
491            Rule::dummy_stmt => return Err(anyhow!("dummy statement")),
492            _ => unreachable!(),
493        };
494        Ok(stmt)
495    }
496}
497
498#[derive(Debug, PartialEq, Eq)]
499pub enum Signature {
500    Type {
501        param: Vec<Cst>,
502        name: Cst,
503        constraint: Vec<Cst>,
504    },
505    Val {
506        var: Cst,
507        signature: Cst,
508        constraint: Vec<Cst>,
509    },
510    Direct {
511        var: Cst,
512        signature: Cst,
513        constraint: Vec<Cst>,
514    },
515}
516
517impl FromCst for Signature {
518    fn from_cst(cst: &Cst) -> Result<Self> {
519        match cst.rule {
520            Rule::sig_type_stmt => {
521                let mut inner = cst.inner.iter().peekable();
522                let mut param = vec![];
523                while inner.peek().ok_or(anyhow!("expect type name"))?.rule == Rule::type_param {
524                    let p = inner.next().unwrap().clone();
525                    param.push(p);
526                }
527                let name = inner.next().unwrap().clone();
528                let constraint = inner.map(|cst| cst.clone()).collect();
529                Ok(Signature::Type {
530                    param,
531                    name,
532                    constraint,
533                })
534            }
535
536            Rule::sig_val_stmt => {
537                let mut inner = cst.inner.iter();
538                let var = inner.next().ok_or(anyhow!("expect var"))?.clone();
539                let signature = inner.next().ok_or(anyhow!("expect signature"))?.clone();
540                let constraint = inner.map(|cst| cst.clone()).collect();
541                Ok(Signature::Val {
542                    var,
543                    signature,
544                    constraint,
545                })
546            }
547
548            Rule::sig_direct_stmt => {
549                let mut inner = cst.inner.iter();
550                let var = inner.next().ok_or(anyhow!("expect var"))?.clone();
551                let signature = inner.next().ok_or(anyhow!("expect signature"))?.clone();
552                let constraint = inner.cloned().collect();
553                Ok(Signature::Direct {
554                    var,
555                    signature,
556                    constraint,
557                })
558            }
559
560            Rule::dummy_sig_stmt => Err(anyhow!("dummy signature statement")),
561            _ => unreachable!(),
562        }
563    }
564}
565
566#[derive(Debug, PartialEq, Eq)]
567pub struct LetRecInner {
568    pub pattern: Cst,
569    pub type_expr: Option<Cst>,
570    pub variant: Vec<LetRecVariant>,
571}
572
573#[derive(Debug, PartialEq, Eq)]
574pub struct LetRecVariant {
575    pub args: Vec<Cst>,
576    pub expr: Cst,
577}
578
579impl FromCst for LetRecInner {
580    fn from_cst(cst: &Cst) -> Result<Self> {
581        let mut inner = cst.inner.iter().peekable();
582        let pattern = inner.next().ok_or(anyhow!("expected pattern"))?.clone();
583        let type_expr = if inner
584            .peek()
585            .ok_or(anyhow!("expected variant or expr"))?
586            .rule
587            == Rule::type_expr
588        {
589            Some(inner.next().unwrap().clone())
590        } else {
591            None
592        };
593        let mut variant = vec![];
594        while inner.peek().is_some() {
595            let mut args = vec![];
596            while inner.peek().ok_or(anyhow!("expected expr"))?.rule == Rule::arg {
597                args.push(inner.next().unwrap().clone())
598            }
599            let expr = inner.next().unwrap().clone();
600            variant.push(LetRecVariant { args, expr });
601        }
602        Ok(LetRecInner {
603            pattern,
604            type_expr,
605            variant,
606        })
607    }
608}
609
610#[derive(Debug, PartialEq, Eq)]
611pub struct TypeInner {
612    pub param: Vec<Cst>,
613    pub name: Cst,
614    pub constraint: Vec<Cst>,
615    pub body: TypeBody,
616}
617
618impl FromCst for TypeInner {
619    fn from_cst(cst: &Cst) -> Result<Self> {
620        let mut inner = cst.inner.iter().peekable();
621        let mut param = vec![];
622        while inner.peek().ok_or(anyhow!("expected type name"))?.rule == Rule::type_param {
623            let p = inner.next().unwrap().clone();
624            param.push(p);
625        }
626        let name = inner.next().unwrap().clone();
627
628        let body = if inner
629            .peek()
630            .ok_or(anyhow!("expected type expr or type variant"))?
631            .rule
632            == Rule::type_expr
633        {
634            TypeBody::Expr(inner.next().unwrap().clone())
635        } else {
636            let mut variants = vec![];
637            while inner.peek().is_some() && inner.peek().unwrap().rule == Rule::type_variant {
638                let v = inner.next().unwrap().clone();
639                variants.push(v);
640            }
641            TypeBody::Variants(variants)
642        };
643        let constraint = inner.cloned().collect();
644        Ok(TypeInner {
645            param,
646            name,
647            constraint,
648            body,
649        })
650    }
651}
652
653#[derive(Debug, PartialEq, Eq)]
654pub enum TypeBody {
655    Variants(Vec<Cst>),
656    Expr(Cst),
657}