presk_syntax/parser/
mod.rs1mod config;
12mod decl;
13mod expr;
14mod ty;
15
16use crate::ast::{Ident, Program};
17use crate::diag::Diagnostic;
18use crate::lexer;
19use crate::source::{FileId, SourceMap, Span};
20use crate::token::{Kw, Op, TokKind, Token};
21
22pub fn parse_file(sm: &SourceMap, file: FileId) -> (Program, Vec<Diagnostic>) {
26 let lexed = lexer::lex(file, sm.text(file));
27 let mut p = Parser { toks: lexed.tokens, pos: 0, free: 0, diags: lexed.diags, file, line_starts: line_starts(sm.text(file)) };
28 let decls = p.program();
29 (Program { file, decls }, p.diags)
30}
31
32pub fn parse_type(sm: &SourceMap, file: FileId) -> (Option<crate::ast::Ty>, Vec<Diagnostic>) {
35 let lexed = lexer::lex(file, sm.text(file));
36 let mut p = Parser { toks: lexed.tokens, pos: 0, free: 1, diags: lexed.diags, file, line_starts: line_starts(sm.text(file)) };
37 p.skip_newlines();
38 let ty = p.ty().ok();
39 p.skip_newlines();
40 if ty.is_some() && !matches!(p.peek_kind(), TokKind::Eof) {
41 let span = p.peek().span;
42 let found = p.peek_kind();
43 p.error_at(span, format!("expected end of type, found {found}"), "unexpected here");
44 }
45 (ty, p.diags)
46}
47
48fn line_starts(text: &str) -> Vec<u32> {
49 let mut v = vec![0];
50 for (i, b) in text.bytes().enumerate() {
51 if b == b'\n' {
52 v.push(i as u32 + 1);
53 }
54 }
55 v
56}
57
58#[derive(Debug)]
60pub(crate) struct ParseError;
61
62pub(crate) type PResult<T> = Result<T, ParseError>;
63
64pub(crate) struct Parser {
65 toks: Vec<Token>,
66 pos: usize,
67 free: u32,
69 diags: Vec<Diagnostic>,
70 file: FileId,
71 line_starts: Vec<u32>,
72}
73
74impl Parser {
75 pub(crate) fn peek(&mut self) -> &Token {
79 if self.free > 0 {
80 while matches!(self.toks[self.pos].kind, TokKind::Newline) {
81 self.pos += 1;
82 }
83 }
84 &self.toks[self.pos]
85 }
86
87 pub(crate) fn peek_kind(&mut self) -> TokKind {
88 self.peek().kind.clone()
89 }
90
91 pub(crate) fn peek_nth(&mut self, n: usize) -> &Token {
93 self.peek();
94 let mut i = self.pos;
95 let mut left = n;
96 while left > 0 {
97 i += 1;
98 if self.free > 0 {
99 while matches!(self.toks[i].kind, TokKind::Newline) {
100 i += 1;
101 }
102 }
103 left -= 1;
104 }
105 &self.toks[i.min(self.toks.len() - 1)]
106 }
107
108 pub(crate) fn bump(&mut self) -> Token {
109 self.peek();
110 let t = self.toks[self.pos].clone();
111 if !matches!(t.kind, TokKind::Eof) {
112 self.pos += 1;
113 }
114 t
115 }
116
117 pub(crate) fn at(&mut self, kind: &TokKind) -> bool {
118 &self.peek().kind == kind
119 }
120
121 pub(crate) fn at_op(&mut self, op: Op) -> bool {
122 self.at(&TokKind::Op(op))
123 }
124
125 pub(crate) fn at_kw(&mut self, kw: Kw) -> bool {
126 self.at(&TokKind::Kw(kw))
127 }
128
129 pub(crate) fn at_word(&mut self, word: &str) -> bool {
131 matches!(&self.peek().kind, TokKind::Ident(s) if s == word)
132 }
133
134 pub(crate) fn eat_op(&mut self, op: Op) -> Option<Token> {
135 if self.at_op(op) { Some(self.bump()) } else { None }
136 }
137
138 pub(crate) fn eat_kw(&mut self, kw: Kw) -> Option<Token> {
139 if self.at_kw(kw) { Some(self.bump()) } else { None }
140 }
141
142 pub(crate) fn expect_op(&mut self, op: Op) -> PResult<Token> {
143 if let Some(t) = self.eat_op(op) { Ok(t) } else { Err(self.unexpected(&format!("`{}`", op.text()))) }
144 }
145
146 pub(crate) fn expect_kw(&mut self, kw: Kw) -> PResult<Token> {
147 if let Some(t) = self.eat_kw(kw) { Ok(t) } else { Err(self.unexpected(&format!("`{}`", kw.text()))) }
148 }
149
150 pub(crate) fn expect_word(&mut self, word: &str) -> PResult<Token> {
151 if self.at_word(word) { Ok(self.bump()) } else { Err(self.unexpected(&format!("`{word}`"))) }
152 }
153
154 pub(crate) fn expect_ident(&mut self, what: &str) -> PResult<Ident> {
155 match self.peek_kind() {
156 TokKind::Ident(name) => {
157 let t = self.bump();
158 Ok(Ident { name, span: t.span })
159 }
160 _ => Err(self.unexpected(what)),
161 }
162 }
163
164 pub(crate) fn skip_newlines(&mut self) {
166 while matches!(self.toks[self.pos].kind, TokKind::Newline) {
167 self.pos += 1;
168 }
169 }
170
171 pub(crate) fn at_newline(&self) -> bool {
172 matches!(self.toks[self.pos].kind, TokKind::Newline)
173 }
174
175 pub(crate) fn free<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
177 self.free += 1;
178 let r = f(self);
179 self.free -= 1;
180 r
181 }
182
183 pub(crate) fn lines<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
185 let saved = self.free;
186 self.free = 0;
187 let r = f(self);
188 self.free = saved;
189 r
190 }
191
192 pub(crate) fn prev_span(&self) -> Span {
193 self.toks[self.pos.saturating_sub(1)].span
194 }
195
196 pub(crate) fn column(&self, span: Span) -> u32 {
197 let line = self.line_starts.partition_point(|&s| s <= span.start).max(1) - 1;
198 span.start - self.line_starts[line]
199 }
200
201 pub(crate) fn unexpected(&mut self, expected: &str) -> ParseError {
204 let t = self.peek().clone();
205 let found = t.kind.to_string();
206 let span = if matches!(t.kind, TokKind::Newline | TokKind::Eof) { Span::new(self.file, t.span.start as usize, t.span.start as usize) } else { t.span };
207 self.diags.push(
208 Diagnostic::error("E0010", format!("expected {expected}, found {found}"))
209 .label(span, format!("expected {expected} here")),
210 );
211 ParseError
212 }
213
214 pub(crate) fn error_at(&mut self, span: Span, message: impl Into<String>, label: impl Into<String>) -> ParseError {
215 self.diags.push(Diagnostic::error("E0011", message).label(span, label));
216 ParseError
217 }
218}