use crate::syntax::ast::AstArgument;
use crate::syntax::ast::AstExpr;
use crate::syntax::ast::AstLiteral;
use crate::syntax::ast::AstParameter;
use crate::syntax::ast::AstStmt;
use crate::syntax::ast::CallArgsP;
use crate::syntax::ast::DefP;
use crate::syntax::ast::Expr;
use crate::syntax::ast::ForP;
use crate::syntax::ast::LambdaP;
use crate::syntax::ast::ParameterP;
use crate::syntax::ast::Stmt;
use crate::syntax::call::CallArgsUnpack;
use crate::syntax::def::DefParams;
use crate::syntax::state::ParserState;
use crate::syntax::DialectTypes;
impl Expr {
pub(crate) fn check_call(
f: AstExpr,
args: Vec<AstArgument>,
parser_state: &mut ParserState<'_>,
) -> Expr {
let args = CallArgsP { args };
if let Err(e) = CallArgsUnpack::unpack(&args, parser_state.codemap) {
parser_state.errors.push(e);
}
Expr::Call(Box::new(f), args)
}
}
pub(crate) fn validate_module(stmt: &AstStmt, parser_state: &mut ParserState) {
fn validate_params(params: &[AstParameter], parser_state: &mut ParserState) {
if !parser_state.dialect.enable_keyword_only_arguments {
for param in params {
if let ParameterP::NoArgs = ¶m.node {
parser_state.error(
param.span,
"* keyword-only-arguments is not allowed in this dialect",
);
}
}
}
if !parser_state.dialect.enable_positional_only_arguments {
for param in params {
if let ParameterP::Slash = ¶m.node {
parser_state.error(
param.span,
"/ positional-only-arguments is not allowed in this dialect",
);
}
}
}
if let Err(e) = DefParams::unpack(params, parser_state.codemap) {
parser_state.errors.push(e);
}
}
fn f(
stmt: &AstStmt,
parser_state: &mut ParserState,
top_level: bool,
inside_for: bool,
inside_def: bool,
) {
let span = stmt.span;
match &stmt.node {
Stmt::Def(DefP { params, body, .. }) => {
if !parser_state.dialect.enable_def {
parser_state.error(span, "`def` is not allowed in this dialect");
}
validate_params(params, parser_state);
f(body, parser_state, false, false, true)
}
Stmt::For(ForP { body, .. }) => {
if top_level && !parser_state.dialect.enable_top_level_stmt {
parser_state.error(span, "`for` cannot be used outside `def` in this dialect")
} else {
f(body, parser_state, false, true, inside_def)
}
}
Stmt::If(..) | Stmt::IfElse(..) => {
if top_level && !parser_state.dialect.enable_top_level_stmt {
parser_state.error(span, "`if` cannot be used outside `def` in this dialect")
} else {
stmt.node
.visit_stmt(|x| f(x, parser_state, false, inside_for, inside_def))
}
}
Stmt::Break if !inside_for => {
parser_state.error(span, "`break` cannot be used outside of a `for` loop")
}
Stmt::Continue if !inside_for => {
parser_state.error(span, "`continue` cannot be used outside of a `for` loop")
}
Stmt::Return(_) if !inside_def => {
parser_state.error(span, "`return` cannot be used outside of a `def` function")
}
Stmt::Load(..) => {
if !top_level {
parser_state.error(span, "`load` must only occur at the top of a module");
}
if !parser_state.dialect.enable_load {
parser_state.error(span, "`load` is not allowed in this dialect");
}
}
_ => stmt
.node
.visit_stmt(|x| f(x, parser_state, top_level, inside_for, inside_def)),
}
}
fn expr(x: &AstExpr, parser_state: &mut ParserState) {
match &x.node {
Expr::Literal(AstLiteral::Ellipsis) => {
if parser_state.dialect.enable_types == DialectTypes::Disable {
parser_state.error(x.span, "`...` is not allowed in this dialect");
}
}
Expr::Lambda(LambdaP { params, .. }) => {
if !parser_state.dialect.enable_lambda {
parser_state.error(x.span, "`lambda` is not allowed in this dialect");
}
validate_params(params, parser_state);
}
_ => {}
}
x.node.visit_expr(|x| expr(x, parser_state));
}
f(stmt, parser_state, true, false, false);
stmt.visit_expr(|x| expr(x, parser_state));
}