use crate::ast::{ Assignment, AstRoot, BinaryOp, Binding, Block, Class, Decl, DeclKind, Expr, ExprKind, Function, InteractiveInput, MemberAssignment, Name, Parameter, Program, ReturnStatement, Stmt, StmtKind, UnaryOp, }; use crate::lexer::decode_string; use crate::{Diagnostic, DiagnosticKind, Span, Token, TokenKind, lex}; /// Select the syntax root without implying any execution or REPL session. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ParseMode { Module, Expression, Interactive, } pub fn parse_ast(source: &str, mode: ParseMode) -> Result { match mode { ParseMode::Module => parse(source).map(AstRoot::Module), ParseMode::Expression => parse_expression(source).map(AstRoot::Expression), ParseMode::Interactive => { let tokens = lex(source)?; syntax::interactive(&tokens, source) .map(AstRoot::Interactive) .map_err(|error| diagnostic(error, &tokens, source.len())) } } } pub fn parse_source_ast( source: &crate::SourceUnit, mode: ParseMode, ) -> Result { parse_ast(source.text(), mode).map_err(|error| source.annotate(error)) } /// Parse a reader snapshot, retaining its origin and resolved revision on error. pub fn parse_source(source: &crate::SourceUnit) -> Result { parse(source.text()).map_err(|error| source.annotate(error)) } pub fn parse_source_expression( source: &crate::SourceUnit, ) -> Result { parse_expression(source.text()).map_err(|error| source.annotate(error)) } /// Parse one or more typed function or class declarations. This is a syntax /// operation: type names and name references are retained without resolution. pub fn parse(source: &str) -> Result { let tokens = lex(source)?; syntax::program(&tokens, source).map_err(|error| diagnostic(error, &tokens, source.len())) } /// Parse exactly one complete expression, useful independently of declarations. pub fn parse_expression(source: &str) -> Result { let tokens = lex(source)?; syntax::expression(&tokens, source).map_err(|error| diagnostic(error, &tokens, source.len())) } fn diagnostic(error: peg::error::ParseError, tokens: &[Token], end: usize) -> Diagnostic { let span = tokens .get(error.location) .map_or(Span::new(end, end), |token| token.span); let expected: Vec = error.expected.tokens().map(str::to_owned).collect(); Diagnostic { kind: DiagnosticKind::Syntax, span, message: format!("expected {}", expected.join(" or ")), expected, } } fn binding_statement(binding: Binding) -> Stmt { Stmt { span: binding.span, kind: StmtKind::Binding(binding), } } fn binary(left: Expr, operation: BinaryOp, right: Expr) -> Expr { Expr { span: left.span.through(right.span), kind: ExprKind::Binary { operation, left: Box::new(left), right: Box::new(right), }, } } enum Suffix { Member(Name), Call(Vec, Span), } enum ClassMember { Field(Parameter), Method(Function), } fn postfix(expression: Expr, suffix: Suffix) -> Expr { match suffix { Suffix::Member(name) => Expr { span: expression.span.through(name.span), kind: ExprKind::Member { object: Box::new(expression), name, }, }, Suffix::Call(arguments, end) => Expr { span: expression.span.through(end), kind: ExprKind::Call { callee: Box::new(expression), arguments, }, }, } } include!("grammar.peg");