1use self::expression::expression;
2use self::statement::outer_statement;
3use std::collections::{HashMap, HashSet};
4use std::fmt::Debug;
5use std::path::{Path, PathBuf};
6use std::rc::Rc;
7use sylt_common::error::Error;
8use sylt_common::Type as RuntimeType;
9use sylt_tokenizer::{PlacedToken, Token, ZERO_SPAN, file_to_tokens};
10
11pub mod expression;
12pub mod statement;
13pub use self::expression::{Expression, ExpressionKind};
14pub use self::statement::{Statement, StatementKind};
15
16pub use sylt_tokenizer::Span;
17
18type T = Token;
19
20pub trait Next {
21 fn next(&self) -> Self;
22}
23
24pub trait Numbered {
25 fn to_number(&self) -> usize;
26}
27
28#[derive(Debug, Clone)]
30pub struct AST {
31 pub modules: Vec<(PathBuf, Module)>,
32}
33
34#[derive(Debug, Clone)]
36pub struct Module {
37 pub span: Span,
38 pub statements: Vec<Statement>,
39}
40
41#[derive(sylt_macro::Next, PartialEq, PartialOrd, Clone, Copy, Debug)]
51pub enum Prec {
52 No,
53 Assert,
54 BoolOr,
55 BoolAnd,
56 Comp,
57 Term,
58 Factor,
59 Index,
60 Arrow,
61}
62
63#[derive(Debug, Copy, Clone)]
68pub enum VarKind {
69 Const,
70 Mutable,
71 ForceConst,
72 ForceMutable,
73}
74
75impl VarKind {
76 pub fn immutable(&self) -> bool {
77 matches!(self, VarKind::Const | VarKind::ForceConst)
78 }
79
80 pub fn force(&self) -> bool {
81 matches!(self, VarKind::ForceConst | VarKind::ForceMutable)
82 }
83}
84
85#[derive(Debug, Copy, Clone)]
87pub enum Op {
88 Nop,
89 Add,
90 Sub,
91 Mul,
92 Div,
93}
94
95#[derive(Debug, Clone)]
96pub struct Identifier {
97 pub span: Span,
98 pub name: String,
99}
100
101#[derive(Debug, Clone)]
124pub enum AssignableKind {
125 Read(Identifier),
126 Call(Box<Assignable>, Vec<Expression>),
128 ArrowCall(Box<Expression>, Box<Assignable>, Vec<Expression>),
130 Access(Box<Assignable>, Identifier),
131 Index(Box<Assignable>, Box<Expression>),
132}
133
134#[derive(Debug, Clone)]
146pub struct Assignable {
147 pub span: Span,
148 pub kind: AssignableKind,
149}
150
151#[derive(Debug, Clone)]
152pub enum TypeKind {
153 Implied,
155 Resolved(RuntimeType),
157 UserDefined(Assignable),
159 Union(Box<Type>, Box<Type>),
161 Fn(Vec<Type>, Box<Type>),
163 Tuple(Vec<Type>),
165 List(Box<Type>),
167 Set(Box<Type>),
169 Dict(Box<Type>, Box<Type>),
171}
172
173#[derive(Debug, Clone)]
175pub struct Type {
176 pub span: Span,
177 pub kind: TypeKind,
178}
179
180type ParseResult<'t, T> = Result<(Context<'t>, T), (Context<'t>, Vec<Error>)>;
181
182#[derive(Debug, Copy, Clone)]
184pub struct Context<'a> {
185 pub skip_newlines: bool,
186 pub tokens: &'a [Token],
188 pub spans: &'a [Span],
190 pub curr: usize,
192 pub file: &'a Path,
194}
195
196impl<'a> Context<'a> {
197 fn new(tokens: &'a [Token], spans: &'a [Span], file: &'a Path) -> Self {
198 Self {
199 skip_newlines: false,
200 tokens,
201 spans,
202 curr: 0,
203 file,
204 }
205 }
206
207 fn span(&self) -> Span {
209 *self.peek().1
210 }
211
212 fn skip(&self, n: usize) -> Self {
214 let mut new = *self;
215 new.curr += n;
216 while self.skip_newlines && matches!(new.token(), T::Newline) {
217 new.curr += 1;
218 }
219 new
220 }
221
222 fn push_skip_newlines(&self, skip_newlines: bool) -> (Self, bool) {
224 let mut new = *self;
225 new.skip_newlines = skip_newlines;
226 (new.skip(0), self.skip_newlines)
228 }
229
230 fn pop_skip_newlines(&self, skip_newlines: bool) -> Self {
232 let mut new = *self;
233 new.skip_newlines = skip_newlines;
234 new
235 }
236
237 fn skip_if(&self, token: T) -> Self {
238 if self.token() == &token {
239 self.skip(1)
240 } else {
241 *self
242 }
243 }
244
245 fn _skip_if_any<const N: usize>(&self, tokens: [T; N]) -> Self {
246 if tokens.iter().any(|t| self.token() == t) {
247 self.skip(1)
248 } else {
249 *self
250 }
251 }
252
253 fn peek(&self) -> (&Token, &Span) {
255 let token = self.tokens.get(self.curr).unwrap_or(&T::EOF);
256 let span = self.spans.get(self.curr).unwrap_or(&ZERO_SPAN);
257 (token, span)
258 }
259
260 fn token(&self) -> &T {
262 &self.peek().0
263 }
264
265 fn eat(&self) -> (&T, Span, Self) {
267 (self.token(), self.span(), self.skip(1))
268 }
269}
270
271#[macro_export]
275macro_rules! syntax_error {
276 ($ctx:expr, $( $msg:expr ),* ) => {
277 {
278 let msg = format!($( $msg ),*).into();
279 Error::SyntaxError {
280 file: $ctx.file.to_path_buf(),
281 span: $ctx.span(),
282 message: Some(msg),
283 }
284 }
285 };
286}
287
288#[macro_export]
290macro_rules! raise_syntax_error {
291 ($ctx:expr, $( $msg:expr ),* ) => {
292 return Err(($ctx.skip(1), vec![syntax_error!($ctx, $( $msg ),*)]))
293 };
294}
295
296#[macro_export]
298macro_rules! expect {
299 ($ctx:expr, $( $token:pat )|+ , $( $msg:expr ),+ ) => {
300 {
301 if !matches!($ctx.token(), $( $token )|* ) {
302 raise_syntax_error!($ctx, $( $msg ),*);
303 }
304 $ctx.skip(1)
305 }
306 };
307
308 ($ctx:expr, $( $token:pat )|+ ) => {
309 expect!($ctx, $( $token )|*, concat!("Expected ", stringify!($( $token )|*)))
310 };
311}
312
313fn parse_type<'t>(ctx: Context<'t>) -> ParseResult<'t, Type> {
315 use RuntimeType::{Bool, Float, Int, String, Void};
316 use TypeKind::*;
317 let span = ctx.span();
318 let (ctx, kind) = match ctx.token() {
319 T::Identifier(name) => match name.as_str() {
320 "void" => (ctx.skip(1), Resolved(Void)),
321 "int" => (ctx.skip(1), Resolved(Int)),
322 "float" => (ctx.skip(1), Resolved(Float)),
323 "bool" => (ctx.skip(1), Resolved(Bool)),
324 "str" => (ctx.skip(1), Resolved(String)),
325 _ => {
326 let (ctx, assignable) = assignable(ctx)?;
327 (ctx, UserDefined(assignable))
328 }
329 },
330
331 T::Fn => {
333 let mut ctx = ctx.skip(1);
334 let mut params = Vec::new();
335 let ret = loop {
337 match ctx.token() {
338 T::Arrow => {
340 ctx = ctx.skip(1);
341 break if let Ok((_ctx, ret)) = parse_type(ctx) {
342 ctx = _ctx; ret
344 } else {
345 Type {
347 span: ctx.span(),
348 kind: Resolved(Void),
349 }
350 };
351 }
352
353 T::EOF => {
354 raise_syntax_error!(ctx, "Didn't expect EOF in type definition");
355 }
356
357 _ => {
359 let (_ctx, param) = parse_type(ctx)?;
360 ctx = _ctx; params.push(param);
362
363 ctx = if matches!(ctx.token(), T::Comma | T::Arrow) {
364 ctx.skip_if(T::Comma)
365 } else {
366 raise_syntax_error!(ctx, "Expected ',' or '->' after type parameter")
367 };
368 }
369 }
370 };
371 (ctx, Fn(params, Box::new(ret)))
372 }
373
374 T::LeftParen => {
376 let mut ctx = ctx.skip(1);
377 let mut types = Vec::new();
378 loop {
380 match ctx.token() {
381 T::RightParen => {
383 ctx = ctx.skip(1);
384 break;
385 }
386
387 T::EOF => {
388 raise_syntax_error!(ctx, "Didn't expect EOF in type definition");
389 }
390
391 _ => {
393 let (_ctx, param) = parse_type(ctx)?;
394 ctx = _ctx; types.push(param);
396
397 ctx = if matches!(ctx.token(), T::Comma | T::RightParen) {
398 ctx.skip_if(T::Comma)
399 } else {
400 raise_syntax_error!(ctx, "Expected ',' or ')' after tuple field")
401 };
402 }
403 }
404 }
405 (ctx, Tuple(types))
406 }
407
408 T::LeftBracket => {
410 let (ctx, ty) = parse_type(ctx.skip(1))?;
412 let ctx = expect!(ctx, T::RightBracket, "Expected ']' after list type");
413 (ctx, List(Box::new(ty)))
414 }
415
416 T::LeftBrace => {
418 let (ctx, ty) = parse_type(ctx.skip(1))?;
422 if matches!(ctx.token(), T::Colon) {
423 let (ctx, value) = parse_type(ctx.skip(1))?;
425 let ctx = expect!(ctx, T::RightBrace, "Expected '}}' after dict type");
426 (ctx, Dict(Box::new(ty), Box::new(value)))
427 } else {
428 let ctx = expect!(ctx, T::RightBrace, "Expected '}}' after set type");
430 (ctx, Set(Box::new(ty)))
431 }
432 }
433
434 t => {
435 raise_syntax_error!(ctx, "No type starts with '{:?}'", t);
436 }
437 };
438
439 let ty = Type { span, kind };
441
442 let (ctx, ty) = if matches!(ctx.token(), T::Pipe) {
444 let (ctx, rest) = parse_type(ctx.skip(1))?;
446 (
447 ctx,
448 Type {
449 span,
450 kind: Union(Box::new(ty), Box::new(rest)),
451 },
452 )
453 } else {
454 (ctx, ty)
455 };
456
457 let (ctx, ty) = if matches!(ctx.token(), T::QuestionMark) {
459 let void = Type {
460 span: ctx.span(),
461 kind: Resolved(Void),
462 };
463 (
464 ctx.skip(1),
465 Type {
466 span,
467 kind: Union(Box::new(ty), Box::new(void)),
468 },
469 )
470 } else {
471 (ctx, ty)
472 };
473
474 Ok((ctx, ty))
475}
476
477fn assignable_call<'t>(ctx: Context<'t>, callee: Assignable) -> ParseResult<'t, Assignable> {
479 let span = ctx.span();
480 let primer = matches!(ctx.token(), T::Prime); let mut ctx = expect!(
482 ctx,
483 T::Prime | T::LeftParen,
484 "Expected '(' or ' when calling function"
485 );
486 let mut args = Vec::new();
487
488 loop {
490 match (ctx.token(), primer) {
491 (T::EOF, _)
493 | (T::Else, _)
494 | (T::RightParen, false)
495 | (T::Dot, true)
496 | (T::Newline, true)
497 | (T::Arrow, true) => {
498 break;
499 }
500
501 _ => {
503 let (_ctx, expr) = expression(ctx)?;
504 ctx = _ctx; args.push(expr);
506
507 ctx = ctx.skip_if(T::Comma);
508 }
509 }
510 }
511
512 let ctx = if !primer {
513 expect!(ctx, T::RightParen, "Expected ')' after calling function")
514 } else {
515 ctx
516 };
517
518 use AssignableKind::Call;
519 let result = Assignable {
520 span,
521 kind: Call(Box::new(callee), args),
522 };
523 sub_assignable(ctx, result)
524}
525
526fn assignable_index<'t>(ctx: Context<'t>, indexed: Assignable) -> ParseResult<'t, Assignable> {
528 let span = ctx.span();
529 let mut ctx = expect!(ctx, T::LeftBracket, "Expected '[' when indexing");
530
531 let (_ctx, expr) = expression(ctx)?;
532 ctx = _ctx; let ctx = expect!(ctx, T::RightBracket, "Expected ']' after index");
534
535 use AssignableKind::Index;
536 let result = Assignable {
537 span,
538 kind: Index(Box::new(indexed), Box::new(expr)),
539 };
540 sub_assignable(ctx, result)
541}
542
543fn assignable_dot<'t>(ctx: Context<'t>, accessed: Assignable) -> ParseResult<'t, Assignable> {
545 use AssignableKind::Access;
546 let (ctx, ident) = if let (T::Identifier(name), span, ctx) = ctx.skip(1).eat() {
547 (
548 ctx,
549 Identifier {
550 name: name.clone(),
551 span,
552 },
553 )
554 } else {
555 raise_syntax_error!(
556 ctx,
557 "Assignable expressions have to start with an identifier"
558 );
559 };
560
561 let access = Assignable {
562 span: ctx.span(),
563 kind: Access(Box::new(accessed), ident),
564 };
565 sub_assignable(ctx, access)
566}
567
568fn sub_assignable<'t>(ctx: Context<'t>, assignable: Assignable) -> ParseResult<'t, Assignable> {
570 match ctx.token() {
571 T::Prime | T::LeftParen => assignable_call(ctx, assignable),
572 T::LeftBracket => assignable_index(ctx, assignable),
573 T::Dot => assignable_dot(ctx, assignable),
574 _ => Ok((ctx, assignable)),
575 }
576}
577
578fn assignable<'t>(ctx: Context<'t>) -> ParseResult<'t, Assignable> {
588 use AssignableKind::*;
589 let outer_span = ctx.span();
590
591 let ident = if let (T::Identifier(name), span) = (ctx.token(), ctx.span()) {
593 Assignable {
594 span: outer_span,
595 kind: Read(Identifier {
596 span,
597 name: name.clone(),
598 }),
599 }
600 } else {
601 raise_syntax_error!(
602 ctx,
603 "Assignable expressions have to start with an identifier"
604 );
605 };
606
607 sub_assignable(ctx.skip(1), ident)
609}
610
611fn module(path: &Path, token_stream: &[PlacedToken]) -> (Vec<PathBuf>, Result<Module, Vec<Error>>) {
620 let tokens: Vec<_> = token_stream.iter().map(|p| p.token.clone()).collect();
621 let spans: Vec<_> = token_stream.iter().map(|p| p.span).collect();
622 let mut ctx = Context::new(&tokens, &spans, path);
623 let mut errors = Vec::new();
624 let mut use_files = Vec::new();
625 let mut statements = Vec::new();
626 while !matches!(ctx.token(), T::EOF) {
627 if matches!(ctx.token(), T::Newline) {
629 ctx = ctx.skip(1);
630 continue;
631 }
632 ctx = match outer_statement(ctx) {
634 Ok((ctx, statement)) => {
635 use StatementKind::*;
636 if let Use { file, .. } = &statement.kind {
638 let file = PathBuf::from(format!("{}.sy", file.name));
639 use_files.push(file);
640 }
641 if !matches!(statement.kind, EmptyStatement) {
643 statements.push(statement);
644 }
645 ctx
646 }
647 Err((mut ctx, mut errs)) => {
648 errors.append(&mut errs);
649
650 while !matches!(ctx.token(), T::EOF | T::Newline) {
652 ctx = ctx.skip(1);
653 }
654 ctx
655 }
656 }
657 }
658
659 if errors.is_empty() {
660 (
661 use_files,
662 Ok(Module {
663 span: Span::zero(),
664 statements,
665 }),
666 )
667 } else {
668 (use_files, Err(errors))
669 }
670}
671
672pub fn find_conflict_markers(file: &Path) -> Vec<Error> {
685 let s = match std::fs::read_to_string(file) {
686 Ok(s) => s,
687 Err(e) => {
688 return vec![if matches!(e.kind(), std::io::ErrorKind::NotFound) {
689 Error::FileNotFound(file.to_path_buf())
690 } else {
691 Error::IOError(Rc::new(e))
692 }]
693 }
694 };
695 let mut errs = Vec::new();
696 for (i, line) in s.lines().enumerate() {
698 if line.starts_with("<<<<<<<") {
699 errs.push(Error::GitConflictError {
700 file: file.to_path_buf(),
701 span: Span {
702 line: i + 1,
703 col_start: 0,
704 col_end: "<<<<<<<".len(),
705 }
706 });
707 }
708 }
709 errs
710}
711
712pub fn tree(path: &Path) -> Result<AST, Vec<Error>> {
722 let mut visited = HashSet::new();
724 let mut to_visit = Vec::new();
726 let root = path.parent().unwrap();
727 to_visit.push(PathBuf::from(path.file_name().unwrap()));
728
729 let mut modules = Vec::new();
730 let mut errors = Vec::new();
731 while let Some(file) = to_visit.pop() {
732 let file = root.join(file);
733 if visited.contains(&file) {
734 continue;
735 }
736 let mut conflict_errors = find_conflict_markers(&file);
738 if !conflict_errors.is_empty() {
739 errors.append(&mut conflict_errors);
740 visited.insert(file);
741 continue;
742 }
743 match file_to_tokens(&file) {
745 Ok(tokens) => {
746 let (mut next, result) = module(&file, &tokens);
748 match result {
749 Ok(module) => modules.push((file.clone(), module)),
750 Err(mut errs) => errors.append(&mut errs),
751 }
752 to_visit.append(&mut next);
753 }
754 Err(_) => {
755 errors.push(Error::FileNotFound(file.clone()));
756 }
757 }
758 visited.insert(file);
759 }
760
761 if errors.is_empty() {
762 Ok(AST { modules })
763 } else {
764 Err(errors)
765 }
766}
767
768#[cfg(test)]
769mod test {
770 use super::*;
771
772 #[macro_export]
773 macro_rules! test {
774 ($f:ident, $name:ident: $str:expr => $ans:pat) => {
775 #[test]
776 fn $name() {
777 let token_stream = ::sylt_tokenizer::string_to_tokens($str);
778 let tokens: Vec<_> = token_stream.iter().map(|p| p.token.clone()).collect();
779 let spans: Vec<_> = token_stream.iter().map(|p| p.span).collect();
780 let path = ::std::path::PathBuf::from(stringify!($name));
781 let result = $f($crate::Context::new(&tokens, &spans, &path));
782 assert!(
783 result.is_ok(),
784 "\nSyntax tree test didn't parse for:\n{}\nErrs: {:?}",
785 $str,
786 result.unwrap_err().1
787 );
788 let (ctx, result) = result.unwrap();
789 assert!(
790 matches!(result.kind, $ans),
791 "\nExpected: {}, but got: {:?}",
792 stringify!($ans),
793 result
794 );
795 assert_eq!(
796 ctx.curr,
797 ctx.tokens.len(),
798 "Parsed too few or too many tokens:\n{}",
799 $str
800 );
801 }
802 };
803 }
804
805 #[macro_export]
806 macro_rules! fail {
807 ($f:ident, $name:ident: $str:expr => $ans:pat) => {
808 #[test]
809 fn $name() {
810 let token_stream = ::sylt_tokenizer::string_to_tokens($str);
811 let tokens: Vec<_> = token_stream.iter().map(|p| p.token.clone()).collect();
812 let spans: Vec<_> = token_stream.iter().map(|p| p.span).collect();
813 let path = ::std::path::PathBuf::from(stringify!($name));
814 let result = $f($crate::Context::new(&tokens, &spans, &path));
815 assert!(
816 result.is_err(),
817 "\nSyntax tree test parsed - when it should have failed - for:\n{}\n",
818 $str,
819 );
820 let (_, result) = result.unwrap_err();
821 assert!(
822 matches!(result, $ans),
823 "\nExpected: {}, but got: {:?}",
824 stringify!($ans),
825 result
826 );
827 }
828 };
829 }
830
831 mod parse_type {
832 use super::*;
833 use RuntimeType as RT;
834 use TypeKind::*;
835
836 test!(parse_type, type_void: "void" => Resolved(RT::Void));
837 test!(parse_type, type_int: "int" => Resolved(RT::Int));
838 test!(parse_type, type_float: "float" => Resolved(RT::Float));
839 test!(parse_type, type_str: "str" => Resolved(RT::String));
840 test!(parse_type, type_unknown_access: "a.A | int" => Union(_, _));
841 test!(parse_type, type_unknown_access_call: "a.b().A | int" => Union(_, _));
842 test!(parse_type, type_unknown: "blargh" => UserDefined(_));
843 test!(parse_type, type_union: "int | int" => Union(_, _));
844 test!(parse_type, type_question: "int?" => Union(_, _));
845 test!(parse_type, type_union_and_question: "int | void | str?" => Union(_, _));
846
847 test!(parse_type, type_fn_no_params: "fn ->" => Fn(_, _));
848 test!(parse_type, type_fn_one_param: "fn int? -> bool" => Fn(_, _));
849 test!(parse_type, type_fn_two_params: "fn int | void, int? -> str?" => Fn(_, _));
850 test!(parse_type, type_fn_only_ret: "fn -> bool?" => Fn(_, _));
851
852 test!(parse_type, type_tuple_one: "(int)" => Tuple(_));
853 test!(parse_type, type_tuple_complex: "(int | float?, str, str,)" => Tuple(_));
854
855 test!(parse_type, type_list_one: "[int]" => List(_));
856 test!(parse_type, type_list_complex: "[int | float?]" => List(_));
857
858 test!(parse_type, type_set_one: "{int}" => Set(_));
859 test!(parse_type, type_set_complex: "{int | float?}" => Set(_));
860
861 test!(parse_type, type_dict_one: "{int : int}" => Dict(_, _));
862 test!(parse_type, type_dict_complex: "{int | float? : int | int | int?}" => Dict(_, _));
863 }
864}