1use rustc_hash::FxHashMap;
4
5use std::{
6 fmt::Display,
7 path::{Path, PathBuf},
8 rc::Rc,
9};
10
11use crate::position::Position;
12
13#[derive(Clone, PartialEq, Eq, Hash)]
14pub struct TypeName {
15 pub name: String,
16}
17
18impl TypeName {
19 pub fn is_no_value(&self) -> bool {
20 self.name == "NoValue"
21 }
22}
23
24impl std::fmt::Debug for TypeName {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 write!(f, "{}", self.name)
27 }
28}
29impl Display for TypeName {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 write!(f, "{}", self.name)
32 }
33}
34
35impl From<&str> for TypeName {
36 fn from(s: &str) -> Self {
37 TypeName { name: s.to_owned() }
38 }
39}
40
41impl From<&String> for TypeName {
42 fn from(s: &String) -> Self {
43 TypeName { name: s.to_owned() }
44 }
45}
46
47#[derive(Clone, Eq)]
48pub struct TypeSymbol {
49 pub name: TypeName,
50 pub position: Position,
51 pub id: SyntaxId,
52}
53
54impl PartialEq for TypeSymbol {
57 fn eq(&self, other: &Self) -> bool {
58 self.name == other.name
59 }
60}
61
62impl std::fmt::Debug for TypeSymbol {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 if std::env::var("VERBOSE").is_ok() {
65 f.debug_struct("TypeSymbol")
66 .field("name", &self.name)
67 .field("position", &self.position)
68 .field("id", &self.id)
69 .finish()
70 } else {
71 write!(f, "TypeSymbol\"{}\"", self.name.name)
72 }
73 }
74}
75
76impl Display for TypeSymbol {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 write!(f, "{}", self.name)
79 }
80}
81
82impl TypeSymbol {
83 pub fn is_placeholder(&self) -> bool {
84 self.name.name == "__placeholder" || self.name.name == "__reserved_word_placeholder"
86 }
87}
88
89#[derive(Clone, Debug, PartialEq, Eq)]
93pub struct TypeHint {
94 pub sym: TypeSymbol,
95 pub args: Vec<TypeHint>,
96 pub position: Position,
97}
98
99impl TypeHint {
100 pub fn as_src(&self) -> String {
102 if self.args.is_empty() {
103 format!("{}", self.sym.name)
104 } else if self.sym.name.name == "Tuple" {
105 let formatted_args = self
106 .args
107 .iter()
108 .map(|a| a.as_src())
109 .collect::<Vec<_>>()
110 .join(", ");
111
112 format!("({})", formatted_args)
113 } else {
114 let formatted_args = self
115 .args
116 .iter()
117 .map(|a| a.as_src())
118 .collect::<Vec<_>>()
119 .join(", ");
120 format!("{}<{}>", self.sym.name, formatted_args)
121 }
122 }
123}
124
125#[derive(Clone, Debug, PartialEq, Eq, Hash)]
126pub struct SymbolName {
127 pub name: String,
128}
129
130impl Display for SymbolName {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 write!(f, "{}", self.name)
133 }
134}
135
136impl SymbolName {
137 pub fn is_underscore(&self) -> bool {
138 self.name == "_"
139 }
140
141 pub fn is_placeholder(&self) -> bool {
142 self.name == "__placeholder" || self.name == "__reserved_word_placeholder"
144 }
145}
146
147impl From<&str> for SymbolName {
148 fn from(s: &str) -> Self {
149 SymbolName { name: s.to_owned() }
150 }
151}
152
153#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
154pub struct InternedSymbolId(pub usize);
155
156#[derive(Clone, PartialEq, Eq)]
161pub struct Symbol {
162 pub position: Position,
163 pub name: SymbolName,
164 pub id: SyntaxId,
165 pub interned_id: InternedSymbolId,
166}
167
168impl Symbol {
169 pub fn new<S: AsRef<str>>(position: Position, name: S, id_gen: &mut IdGenerator) -> Self {
170 let name = SymbolName {
171 name: name.as_ref().to_owned(),
172 };
173
174 Self {
175 interned_id: id_gen.intern_symbol(&name),
176 position,
177 name,
178 id: id_gen.next(),
179 }
180 }
181
182 pub fn is_placeholder(&self) -> bool {
183 self.name.is_placeholder()
184 }
185}
186
187impl std::fmt::Debug for Symbol {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 if std::env::var("VERBOSE").is_ok() {
190 f.debug_struct("Symbol")
191 .field("name", &self.name)
192 .field("position", &self.position)
193 .field("id", &self.id)
194 .field("interned_id", &self.interned_id)
195 .finish()
196 } else {
197 write!(f, "Symbol\"{}\"", self.name.name)
198 }
199 }
200}
201
202#[derive(Clone, Debug, PartialEq, Eq)]
203pub struct SymbolWithHint {
204 pub symbol: Symbol,
205 pub hint: Option<TypeHint>,
206}
207
208#[derive(Debug, Clone, Copy, PartialEq, Eq)]
209pub enum BinaryOperatorKind {
210 Add,
211 Subtract,
212 Multiply,
213 Divide,
214 Modulo,
215 Exponent,
216 Equal,
217 NotEqual,
218 LessThan,
219 LessThanOrEqual,
220 GreaterThan,
221 GreaterThanOrEqual,
222 And,
223 Or,
224 StringConcat,
225}
226
227impl Display for BinaryOperatorKind {
228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229 let s = match self {
230 BinaryOperatorKind::Add => "+",
231 BinaryOperatorKind::Subtract => "-",
232 BinaryOperatorKind::Multiply => "*",
233 BinaryOperatorKind::Divide => "/",
234 BinaryOperatorKind::Modulo => "%",
235 BinaryOperatorKind::Exponent => "^",
236 BinaryOperatorKind::Equal => "==",
237 BinaryOperatorKind::NotEqual => "!=",
238 BinaryOperatorKind::LessThan => "<",
239 BinaryOperatorKind::LessThanOrEqual => "<=",
240 BinaryOperatorKind::GreaterThan => ">",
241 BinaryOperatorKind::GreaterThanOrEqual => ">=",
242 BinaryOperatorKind::And => "&&",
243 BinaryOperatorKind::Or => "||",
244 BinaryOperatorKind::StringConcat => "^",
245 };
246 write!(f, "{}", s)
247 }
248}
249
250#[derive(Debug, Clone, Copy, PartialEq, Eq)]
251pub enum AssignUpdateKind {
252 Add,
253 Subtract,
254}
255
256impl AssignUpdateKind {
257 pub fn as_src(&self) -> &'static str {
258 match self {
259 AssignUpdateKind::Add => "+=",
260 AssignUpdateKind::Subtract => "-=",
261 }
262 }
263}
264
265#[derive(Debug, Clone, PartialEq, Eq)]
274pub struct Pattern {
275 pub variant_sym: Symbol,
277 pub payload: Option<LetDestination>,
279}
280
281#[derive(Debug, Clone, PartialEq, Eq)]
282pub struct ExpressionWithComma {
283 pub expr: Rc<Expression>,
284 pub comma: Option<Position>,
285}
286
287#[derive(Debug, Clone, PartialEq, Eq)]
288pub struct ParenthesizedExpression {
289 pub open_paren: Position,
290 pub expr: Rc<Expression>,
291 pub close_paren: Position,
292}
293
294#[derive(Debug, Clone, PartialEq, Eq)]
295pub struct ParenthesizedArguments {
296 pub open_paren: Position,
297 pub arguments: Vec<ExpressionWithComma>,
298 pub close_paren: Position,
299}
300
301#[derive(Debug, Clone, PartialEq, Eq)]
302pub enum LetDestination {
303 Symbol(Symbol),
307 Destructure(Vec<Symbol>),
311}
312
313#[derive(Debug, Clone, PartialEq, Eq)]
314pub enum Expression_ {
315 Match(Rc<Expression>, Vec<(Pattern, Block)>),
323 If(Rc<Expression>, Block, Option<Block>),
328 While(Rc<Expression>, Block),
332 ForIn(LetDestination, Rc<Expression>, Block),
337 Break,
341 Continue,
345 Assign(Symbol, Rc<Expression>),
349 AssignUpdate(Symbol, AssignUpdateKind, Rc<Expression>),
354 Let(LetDestination, Option<TypeHint>, Rc<Expression>),
360 Return(Option<Rc<Expression>>),
365 IntLiteral(i64),
369 StringLiteral(String),
373 ListLiteral(Vec<ExpressionWithComma>),
377 TupleLiteral(Vec<Rc<Expression>>),
383 StructLiteral(TypeSymbol, Vec<(Symbol, Rc<Expression>)>),
390 BinaryOperator(Rc<Expression>, BinaryOperatorKind, Rc<Expression>),
396 Variable(Symbol),
400 Call(Rc<Expression>, ParenthesizedArguments),
404 MethodCall(Rc<Expression>, Symbol, ParenthesizedArguments),
408 DotAccess(Rc<Expression>, Symbol),
412 FunLiteral(FunInfo),
416 Assert(Rc<Expression>),
420 Parentheses(Position, Rc<Expression>, Position),
427 Invalid,
430}
431
432impl Expression_ {
433 pub(crate) fn is_invalid_or_placeholder(&self) -> bool {
434 match self {
435 Expression_::Variable(sym) => sym.is_placeholder(),
436 Expression_::Invalid => true,
437 _ => false,
438 }
439 }
440}
441
442#[derive(Clone, PartialEq, Eq, Hash, Copy)]
445pub struct SyntaxId(pub usize);
446
447impl std::fmt::Debug for SyntaxId {
448 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
449 write!(f, "SyntaxId({})", self.0)
457 }
458}
459
460#[derive(Debug, Clone, PartialEq, Eq, Hash)]
463pub enum AstId {
464 Expr(SyntaxId),
466 Sym(SyntaxId),
473 TypeSym(SyntaxId),
479 Import(SyntaxId),
485}
486
487impl AstId {
488 pub fn id(&self) -> SyntaxId {
489 match self {
490 AstId::Expr(syntax_id) => *syntax_id,
491 AstId::Sym(syntax_id) => *syntax_id,
492 AstId::TypeSym(syntax_id) => *syntax_id,
493 AstId::Import(syntax_id) => *syntax_id,
494 }
495 }
496}
497
498#[derive(Debug, Clone)]
499pub struct IdGenerator {
500 pub next_id: SyntaxId,
501 pub interned: FxHashMap<SymbolName, InternedSymbolId>,
502 pub intern_id_to_name: FxHashMap<InternedSymbolId, SymbolName>,
503}
504
505impl Default for IdGenerator {
506 fn default() -> Self {
507 Self {
508 next_id: SyntaxId(0),
509 interned: FxHashMap::default(),
510 intern_id_to_name: FxHashMap::default(),
511 }
512 }
513}
514
515impl IdGenerator {
516 #[allow(clippy::should_implement_trait)]
517 pub fn next(&mut self) -> SyntaxId {
518 let next_id = self.next_id;
519 self.next_id = SyntaxId(next_id.0 + 1);
520 next_id
521 }
522
523 pub fn intern_symbol(&mut self, name: &SymbolName) -> InternedSymbolId {
524 match self.interned.get(name) {
525 Some(id) => *id,
526 None => {
527 let id = InternedSymbolId(self.interned.len());
528 self.interned.insert(name.clone(), id);
529 self.intern_id_to_name.insert(id, name.clone());
530 id
531 }
532 }
533 }
534}
535
536#[derive(Debug, Clone, Default)]
538pub struct Vfs {
539 file_srcs: FxHashMap<PathBuf, String>,
542}
543
544impl Vfs {
545 pub fn insert(&mut self, path: PathBuf, src: String) {
546 self.file_srcs.insert(path, src);
547 }
548
549 pub fn file_src(&self, path: &Path) -> Option<&String> {
550 self.file_srcs.get(path)
551 }
552
553 pub fn pos_src(&self, pos: &Position) -> Option<&str> {
554 match self.file_srcs.get(pos.path.as_path()) {
555 Some(file) => Some(&file[pos.start_offset..pos.end_offset]),
556 None => None,
557 }
558 }
559}
560
561#[derive(Debug, Clone, PartialEq, Eq)]
562pub struct Expression {
563 pub position: Position,
564 pub expr_: Expression_,
565 pub value_is_used: bool,
569 pub id: SyntaxId,
570}
571
572impl Expression {
573 pub(crate) fn new(position: Position, expr_: Expression_, id: SyntaxId) -> Self {
574 Self {
575 position,
576 expr_,
577 value_is_used: true,
578 id,
579 }
580 }
581
582 pub fn invalid(position: Position, id: SyntaxId) -> Self {
584 Self {
585 position,
586 expr_: Expression_::Invalid,
587 value_is_used: true,
588 id,
589 }
590 }
591}
592
593#[derive(Debug, Clone, PartialEq, Eq)]
594pub struct Block {
595 pub open_brace: Position,
596 pub exprs: Vec<Rc<Expression>>,
597 pub close_brace: Position,
598}
599
600#[derive(Debug, Clone, PartialEq, Eq)]
601pub enum Visibility {
602 External(Position),
603 CurrentFile,
604}
605
606#[derive(Debug, Clone, PartialEq, Eq)]
607pub struct ToplevelExpression(pub Expression);
608
609#[derive(Debug, Clone, PartialEq, Eq)]
610pub struct FunInfo {
611 pub pos: Position,
612 pub doc_comment: Option<String>,
613 pub name_sym: Option<Symbol>,
615 pub item_id: Option<ToplevelItemId>,
617 pub type_params: Vec<TypeSymbol>,
618 pub params: ParenthesizedParameters,
619 pub return_hint: Option<TypeHint>,
620 pub body: Block,
621}
622
623#[derive(Debug, Clone, PartialEq, Eq)]
624pub struct ParenthesizedParameters {
625 pub open_paren: Position,
626 pub params: Vec<SymbolWithHint>,
627 pub close_paren: Position,
628}
629
630#[derive(Debug, Clone, PartialEq, Eq)]
631pub struct TestInfo {
632 pub pos: Position,
633 pub doc_comment: Option<String>,
634 pub name_sym: Symbol,
635 pub body: Block,
636}
637
638#[derive(Debug, Clone, PartialEq, Eq)]
639pub struct VariantInfo {
640 pub name_sym: Symbol,
641 pub payload_hint: Option<TypeHint>,
644}
645
646#[derive(Debug, Clone, PartialEq, Eq)]
647pub struct FieldInfo {
648 pub sym: Symbol,
649 pub hint: TypeHint,
650 pub doc_comment: Option<String>,
651}
652
653#[derive(Debug, Clone, PartialEq, Eq)]
654pub struct EnumInfo {
655 pub pos: Position,
656 pub visibility: Visibility,
657 pub doc_comment: Option<String>,
658 pub name_sym: TypeSymbol,
659 pub type_params: Vec<TypeSymbol>,
660 pub variants: Vec<VariantInfo>,
661}
662
663#[derive(Debug, Clone, PartialEq, Eq)]
664pub struct StructInfo {
665 pub pos: Position,
666 pub visibility: Visibility,
667 pub doc_comment: Option<String>,
668 pub name_sym: TypeSymbol,
669 pub type_params: Vec<TypeSymbol>,
670 pub fields: Vec<FieldInfo>,
676}
677
678#[derive(Debug, Clone, PartialEq, Eq)]
679pub struct ImportInfo {
680 pub pos: Position,
681 pub path: PathBuf,
684 pub path_pos: Position,
687 pub id: SyntaxId,
688}
689
690#[derive(Debug, Clone, Copy, PartialEq, Eq)]
691pub enum BuiltinMethodKind {
692 ListAppend,
693 ListContains,
694 ListGet,
695 ListLen,
696 PathExists,
697 PathRead,
698 StringIndexOf,
699 StringLen,
700 StringLines,
701 StringSubstring,
702}
703
704#[derive(Debug, Clone, PartialEq, Eq)]
705pub enum MethodKind {
706 BuiltinMethod(BuiltinMethodKind, Option<FunInfo>),
707 UserDefinedMethod(FunInfo),
708}
709
710#[derive(Debug, Clone, PartialEq, Eq)]
711pub struct MethodInfo {
712 pub pos: Position,
713 pub receiver_hint: TypeHint,
715 pub receiver_sym: Symbol,
721 pub name_sym: Symbol,
724 pub kind: MethodKind,
726}
727
728impl MethodInfo {
729 pub fn fun_info(&self) -> Option<&FunInfo> {
730 match &self.kind {
731 MethodKind::BuiltinMethod(_, fun_info) => fun_info.as_ref(),
732 MethodKind::UserDefinedMethod(fun_info) => Some(fun_info),
733 }
734 }
735
736 pub fn full_name(&self) -> String {
737 format!("{}::{}", self.receiver_hint.sym, self.name_sym.name)
738 }
739}
740
741#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
742pub struct ToplevelItemId(pub usize);
743
744#[derive(Debug, Clone, PartialEq, Eq)]
745pub enum ToplevelItem {
746 Fun(Symbol, FunInfo, Visibility),
751 Method(MethodInfo, Visibility),
756 Test(TestInfo),
760 Enum(EnumInfo),
764 Struct(StructInfo),
768 Import(ImportInfo),
772 Expr(ToplevelExpression),
778 Block(Block),
782}
783
784impl ToplevelItem {
785 pub fn position(&self) -> Position {
786 match self {
787 ToplevelItem::Fun(_, fun_info, _) => fun_info.pos.clone(),
788 ToplevelItem::Method(method_info, _) => method_info.pos.clone(),
789 ToplevelItem::Test(test_info) => test_info.pos.clone(),
790 ToplevelItem::Enum(enum_info) => enum_info.pos.clone(),
791 ToplevelItem::Struct(struct_info) => struct_info.pos.clone(),
792 ToplevelItem::Import(import_info) => import_info.pos.clone(),
793 ToplevelItem::Expr(toplevel_expression) => toplevel_expression.0.position.clone(),
794 ToplevelItem::Block(block) => Position::merge(&block.open_brace, &block.close_brace),
795 }
796 }
797
798 pub(crate) fn is_invalid_or_placeholder(&self) -> bool {
799 match self {
800 ToplevelItem::Fun(symbol, _, _) => symbol.is_placeholder(),
801 ToplevelItem::Method(method_info, _) => method_info.name_sym.is_placeholder(),
802 ToplevelItem::Test(test_info) => test_info.name_sym.is_placeholder(),
803 ToplevelItem::Enum(enum_info) => enum_info.name_sym.is_placeholder(),
804 ToplevelItem::Struct(struct_info) => struct_info.name_sym.is_placeholder(),
805 ToplevelItem::Expr(e) => e.0.expr_.is_invalid_or_placeholder(),
806 ToplevelItem::Block(_) => false,
807 ToplevelItem::Import(_) => false,
808 }
809 }
810}