use crate::error::{Error, Result};
use crate::lexer::{StringPart, Token, TokenKind};
mod ast;
mod checks;
mod cursor;
mod decls;
mod expr;
mod imports;
mod objects;
mod types;
mod validate;
pub use ast::{
Annotation, BinOp, Body, Entry, Expr, ForGenerator, Import, LocalBindings, Modifier, Module,
Property, StringInterpPart, TraceSite, TypeExpr, UnOp, WhenGenerator,
};
pub(crate) use ast::{has_untyped_result_new, infer_method_return_new, rewrite_untyped_result_new};
use ast::{infers_new, type_expr_runtime_name};
use checks::*;
use cursor::*;
use decls::*;
pub use imports::collect_imports;
pub(crate) use imports::collect_imports_with_kind;
use objects::*;
pub fn parse(tokens: &[Token]) -> Result<Module> {
parse_named(tokens, "", "<input>")
}
pub fn parse_named(tokens: &[Token], source: &str, name: &str) -> Result<Module> {
let mut p = Parser::new(tokens, source, name);
p.parse_module()
}
pub fn parse_expr_tokens(tokens: &[Token], source: &str, name: &str) -> Result<Expr> {
let mut p = Parser::new(tokens, source, name);
let expr = p.parse_expr()?;
if !p.at_eof() {
return Err(p.unexpected_token("end of file"));
}
Ok(expr)
}
#[cfg(feature = "eval-core")]
pub(crate) fn parse_type_name(name: &str) -> Result<TypeExpr> {
let tokens = crate::lexer::lex(name)?;
Parser::new(&tokens, name, "<type>").parse_type()
}
pub const MAX_NESTING_DEPTH: usize = 128;
#[derive(Default)]
struct MemberHeader {
doc_comment: Option<usize>,
annotations: Vec<Annotation>,
annotations_start: Option<usize>,
modifiers: Vec<(Modifier, usize)>,
}
impl MemberHeader {
fn is_empty(&self) -> bool {
self.doc_comment.is_none() && self.annotations.is_empty() && self.modifiers.is_empty()
}
fn start(&self) -> Option<usize> {
self.doc_comment
.or(self.annotations_start)
.or(self.modifiers.first().map(|(_, offset)| *offset))
}
fn modifiers(&self) -> Vec<Modifier> {
self.modifiers.iter().map(|(m, _)| m.clone()).collect()
}
fn has(&self, modifier: Modifier) -> bool {
self.modifiers.iter().any(|(m, _)| *m == modifier)
}
}
#[derive(Clone, Copy)]
enum MemberKind {
Module,
AmendingModule,
Class,
TypeAlias,
Method,
Property,
ObjectMember,
}
impl MemberKind {
fn allows(self, modifier: &Modifier) -> bool {
use Modifier::*;
match self {
MemberKind::Module => matches!(modifier, Abstract | Open),
MemberKind::AmendingModule => false,
MemberKind::Class => matches!(modifier, Abstract | Open | Local | External),
MemberKind::TypeAlias => matches!(modifier, Local | External),
MemberKind::Method => matches!(modifier, Abstract | Local | External | Const),
MemberKind::Property => {
matches!(
modifier,
Abstract | Local | Hidden | External | Fixed | Const
)
}
MemberKind::ObjectMember => matches!(modifier, Local | Const),
}
}
fn description(self) -> &'static str {
match self {
MemberKind::Module => "modules",
MemberKind::AmendingModule => "modules that amend another module",
MemberKind::Class => "classes",
MemberKind::TypeAlias => "type aliases",
MemberKind::Method => "methods",
MemberKind::Property => "properties",
MemberKind::ObjectMember => "object members",
}
}
}
struct Parser<'a> {
tokens: &'a [Token],
source: &'a str,
name: &'a str,
pos: usize,
import_exprs: Vec<String>,
prev_end: usize,
prev_line: usize,
amending: bool,
new_types: Vec<(String, usize)>,
type_alias_parameters: std::collections::HashMap<String, Vec<String>>,
local_type_aliases: std::collections::HashSet<String>,
module_local_type_aliases: std::collections::HashSet<String>,
depth: usize,
}