use super::*;
use crate::stdlib::_ast::argument::{
KeywordArguments, PositionalArguments, merge_class_def_args, split_class_def_args,
};
use crate::stdlib::_ast::exception::except_handler_from_object_unvalidated_range;
use crate::stdlib::_ast::type_parameters::type_params_from_field;
use rustpython_compiler_core::SourceFile;
fn runtime_decorator_expr_list(values: &[Option<ast::Decorator>]) -> Vec<Option<ast::Expr>> {
values
.iter()
.map(|value| value.as_ref().map(|decorator| decorator.expression.clone()))
.collect()
}
fn lower_runtime_decorator_list(values: Vec<Option<ast::Decorator>>) -> Vec<ast::Decorator> {
values
.into_iter()
.map(|value| {
value.unwrap_or_else(|| ast::Decorator {
range: Default::default(),
node_index: Default::default(),
expression: runtime_null_expr_placeholder(),
})
})
.collect()
}
fn definition_range_from_name(
source_file: &SourceFile,
name_start: TextSize,
end: TextSize,
keyword: &str,
) -> TextRange {
let source_code = source_file.to_source_code();
let line = source_code.line_index(name_start);
let line_start = source_code.line_start(line);
let keyword_start = source_code
.slice(TextRange::new(line_start, name_start))
.rfind(keyword)
.map_or(line_start, |offset| {
line_start + TextSize::new(offset as u32)
});
TextRange::new(keyword_start, end)
}
fn runtime_stmt_type_comment(
vm: &VirtualMachine,
type_comment: Option<PyObjectRef>,
) -> (Option<Box<str>>, Option<Vec<u8>>) {
type_comment.map_or((None, None), |type_comment| {
super::constant::runtime_string_from_pyobject(vm, &type_comment)
})
}
fn runtime_stmt_type_comment_object(
vm: &VirtualMachine,
value: Option<Box<str>>,
bytes: Option<Vec<u8>>,
) -> PyObjectRef {
super::constant::runtime_stmt_type_comment_object(vm, value, bytes)
.unwrap_or_else(|| vm.ctx.none())
}
impl Node for ast::Stmt {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
match self {
Self::FunctionDef(cons) => cons.ast_to_object(vm, source_file),
Self::ClassDef(cons) => cons.ast_to_object(vm, source_file),
Self::Return(cons) => cons.ast_to_object(vm, source_file),
Self::Delete(cons) => cons.ast_to_object(vm, source_file),
Self::Assign(cons) => cons.ast_to_object(vm, source_file),
Self::TypeAlias(cons) => cons.ast_to_object(vm, source_file),
Self::AugAssign(cons) => cons.ast_to_object(vm, source_file),
Self::AnnAssign(cons) => cons.ast_to_object(vm, source_file),
Self::For(cons) => cons.ast_to_object(vm, source_file),
Self::While(cons) => cons.ast_to_object(vm, source_file),
Self::If(cons) => cons.ast_to_object(vm, source_file),
Self::With(cons) => cons.ast_to_object(vm, source_file),
Self::Match(cons) => cons.ast_to_object(vm, source_file),
Self::Raise(cons) => cons.ast_to_object(vm, source_file),
Self::Try(cons) => cons.ast_to_object(vm, source_file),
Self::Assert(cons) => cons.ast_to_object(vm, source_file),
Self::Import(cons) => cons.ast_to_object(vm, source_file),
Self::ImportFrom(cons) => cons.ast_to_object(vm, source_file),
Self::Global(cons) => cons.ast_to_object(vm, source_file),
Self::Nonlocal(cons) => cons.ast_to_object(vm, source_file),
Self::Expr(cons) => cons.ast_to_object(vm, source_file),
Self::Pass(cons) => cons.ast_to_object(vm, source_file),
Self::Break(cons) => cons.ast_to_object(vm, source_file),
Self::Continue(cons) => cons.ast_to_object(vm, source_file),
Self::IpyEscapeCommand(_) => {
unreachable!("IPython escape command is not part of Python AST")
}
}
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
object: PyObjectRef,
) -> PyResult<Self> {
if vm.is_none(&object) {
return Err(vm.new_value_error("None disallowed in statement list"));
}
enum StmtKind {
FunctionDef { is_async: bool },
ClassDef,
Return,
Delete,
Assign,
TypeAlias,
AugAssign,
AnnAssign,
For { is_async: bool },
While,
If,
With { is_async: bool },
Match,
Raise,
Try { is_star: bool },
Assert,
Import,
ImportFrom,
Global,
Nonlocal,
Expr,
Pass,
Break,
Continue,
}
let kind = if is_node_instance(vm, &object, pyast::NodeStmtFunctionDef::static_type())? {
StmtKind::FunctionDef { is_async: false }
} else if is_node_instance(vm, &object, pyast::NodeStmtAsyncFunctionDef::static_type())? {
StmtKind::FunctionDef { is_async: true }
} else if is_node_instance(vm, &object, pyast::NodeStmtClassDef::static_type())? {
StmtKind::ClassDef
} else if is_node_instance(vm, &object, pyast::NodeStmtReturn::static_type())? {
StmtKind::Return
} else if is_node_instance(vm, &object, pyast::NodeStmtDelete::static_type())? {
StmtKind::Delete
} else if is_node_instance(vm, &object, pyast::NodeStmtAssign::static_type())? {
StmtKind::Assign
} else if is_node_instance(vm, &object, pyast::NodeStmtTypeAlias::static_type())? {
StmtKind::TypeAlias
} else if is_node_instance(vm, &object, pyast::NodeStmtAugAssign::static_type())? {
StmtKind::AugAssign
} else if is_node_instance(vm, &object, pyast::NodeStmtAnnAssign::static_type())? {
StmtKind::AnnAssign
} else if is_node_instance(vm, &object, pyast::NodeStmtFor::static_type())? {
StmtKind::For { is_async: false }
} else if is_node_instance(vm, &object, pyast::NodeStmtAsyncFor::static_type())? {
StmtKind::For { is_async: true }
} else if is_node_instance(vm, &object, pyast::NodeStmtWhile::static_type())? {
StmtKind::While
} else if is_node_instance(vm, &object, pyast::NodeStmtIf::static_type())? {
StmtKind::If
} else if is_node_instance(vm, &object, pyast::NodeStmtWith::static_type())? {
StmtKind::With { is_async: false }
} else if is_node_instance(vm, &object, pyast::NodeStmtAsyncWith::static_type())? {
StmtKind::With { is_async: true }
} else if is_node_instance(vm, &object, pyast::NodeStmtMatch::static_type())? {
StmtKind::Match
} else if is_node_instance(vm, &object, pyast::NodeStmtRaise::static_type())? {
StmtKind::Raise
} else if is_node_instance(vm, &object, pyast::NodeStmtTry::static_type())? {
StmtKind::Try { is_star: false }
} else if is_node_instance(vm, &object, pyast::NodeStmtTryStar::static_type())? {
StmtKind::Try { is_star: true }
} else if is_node_instance(vm, &object, pyast::NodeStmtAssert::static_type())? {
StmtKind::Assert
} else if is_node_instance(vm, &object, pyast::NodeStmtImport::static_type())? {
StmtKind::Import
} else if is_node_instance(vm, &object, pyast::NodeStmtImportFrom::static_type())? {
StmtKind::ImportFrom
} else if is_node_instance(vm, &object, pyast::NodeStmtGlobal::static_type())? {
StmtKind::Global
} else if is_node_instance(vm, &object, pyast::NodeStmtNonlocal::static_type())? {
StmtKind::Nonlocal
} else if is_node_instance(vm, &object, pyast::NodeStmtExpr::static_type())? {
StmtKind::Expr
} else if is_node_instance(vm, &object, pyast::NodeStmtPass::static_type())? {
StmtKind::Pass
} else if is_node_instance(vm, &object, pyast::NodeStmtBreak::static_type())? {
StmtKind::Break
} else if is_node_instance(vm, &object, pyast::NodeStmtContinue::static_type())? {
StmtKind::Continue
} else {
return Err(vm.new_type_error(format!(
"expected some sort of stmt, but got {}",
object.repr(vm)?
)));
};
let range = stmt_range_from_object(vm, source_file, &object)?;
Ok(match kind {
StmtKind::FunctionDef { is_async } => {
Self::FunctionDef(stmt_function_def_from_object_with_range(
vm,
source_file,
&object,
range,
is_async,
)?)
}
StmtKind::ClassDef => Self::ClassDef(stmt_class_def_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Return => Self::Return(stmt_return_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Delete => Self::Delete(stmt_delete_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Assign => Self::Assign(stmt_assign_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::TypeAlias => Self::TypeAlias(stmt_type_alias_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::AugAssign => Self::AugAssign(stmt_aug_assign_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::AnnAssign => Self::AnnAssign(stmt_ann_assign_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::For { is_async } => Self::For(stmt_for_from_object_with_range(
vm,
source_file,
&object,
range,
is_async,
)?),
StmtKind::While => Self::While(stmt_while_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::If => Self::If(elif_else_clause::ast_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::With { is_async } => Self::With(stmt_with_from_object_with_range(
vm,
source_file,
&object,
range,
is_async,
)?),
StmtKind::Match => Self::Match(stmt_match_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Raise => Self::Raise(stmt_raise_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Try { is_star } => Self::Try(stmt_try_from_object_with_range(
vm,
source_file,
&object,
range,
is_star,
)?),
StmtKind::Assert => Self::Assert(stmt_assert_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Import => Self::Import(stmt_import_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::ImportFrom => Self::ImportFrom(stmt_import_from_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Global => Self::Global(stmt_global_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Nonlocal => Self::Nonlocal(stmt_nonlocal_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Expr => Self::Expr(stmt_expr_from_object_with_range(
vm,
source_file,
&object,
range,
)?),
StmtKind::Pass => Self::Pass(stmt_pass_from_object_with_range(range)),
StmtKind::Break => Self::Break(stmt_break_from_object_with_range(range)),
StmtKind::Continue => Self::Continue(stmt_continue_from_object_with_range(range)),
})
}
}
fn stmt_function_def_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
is_async: bool,
) -> PyResult<ast::StmtFunctionDef> {
let typ = if is_async {
"AsyncFunctionDef"
} else {
"FunctionDef"
};
let name = get_required_identifier_field(vm, source_file, object, "name", typ)?;
let parameters = Node::ast_from_object(
vm,
source_file,
get_node_field_required(vm, object, "args", typ)?,
)?;
let body: Vec<Option<ast::Stmt>> = get_node_list_field(vm, source_file, object, "body", typ)?;
let decorator_list: Vec<Option<ast::Decorator>> =
get_node_list_field(vm, source_file, object, "decorator_list", typ)?;
let runtime_decorator_exprs = runtime_decorator_expr_list(&decorator_list);
let runtime_body = runtime_stmt_list_metadata(&body);
let runtime_decorator_list = runtime_expr_list_metadata(&runtime_decorator_exprs);
let body = lower_runtime_stmt_list(body);
let decorator_list = lower_runtime_decorator_list(decorator_list);
let returns = get_node_field_opt(vm, object, "returns")?
.map(|obj| Node::ast_from_object(vm, source_file, obj))
.transpose()?;
let (runtime_type_comment, runtime_type_comment_bytes) =
runtime_stmt_type_comment(vm, get_ast_string_field_opt(vm, object, "type_comment")?);
let type_params = type_params_from_field(vm, source_file, object, "type_params", typ)?;
Ok(ast::StmtFunctionDef {
node_index: Default::default(),
name,
parameters,
body,
decorator_list: decorator_list.into(),
returns,
type_params,
range,
is_async,
runtime_decorator_list,
runtime_type_comment,
runtime_type_comment_bytes,
runtime_body,
})
}
impl Node for ast::StmtFunctionDef {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
name,
parameters,
body,
decorator_list,
returns,
type_params,
is_async,
range,
runtime_decorator_list,
runtime_type_comment,
runtime_type_comment_bytes,
runtime_body,
} = self;
let range = definition_range_from_name(
source_file,
name.range.start(),
range.end(),
if is_async { "async" } else { "def" },
);
let cls = if !is_async {
pyast::NodeStmtFunctionDef::static_type().to_owned()
} else {
pyast::NodeStmtAsyncFunctionDef::static_type().to_owned()
};
let node = NodeAst.into_ref_with_type(vm, cls).unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("name", name.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("args", parameters.ast_to_object(vm, source_file), vm)
.unwrap();
let body = runtime_body.map_or_else(
|| body.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("body", body, vm).unwrap();
dict.set_item(
"decorator_list",
runtime_decorator_list.map_or_else(
|| decorator_list.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
),
vm,
)
.unwrap();
dict.set_item("returns", returns.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item(
"type_comment",
runtime_stmt_type_comment_object(vm, runtime_type_comment, runtime_type_comment_bytes),
vm,
)
.unwrap();
dict.set_item(
"type_params",
type_params.map_or_else(
|| vm.ctx.new_list(vec![]).into(),
|tp| tp.ast_to_object(vm, source_file),
),
vm,
)
.unwrap();
node_add_location(&dict, range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let is_async =
is_node_instance(vm, &_object, pyast::NodeStmtAsyncFunctionDef::static_type())?;
let typ = if is_async {
"AsyncFunctionDef"
} else {
"FunctionDef"
};
let range = range_from_object(vm, source_file, &_object, typ)?;
stmt_function_def_from_object_with_range(vm, source_file, &_object, range, is_async)
}
}
fn stmt_class_def_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtClassDef> {
let name = get_required_identifier_field(vm, source_file, object, "name", "ClassDef")?;
let bases = PositionalArguments::ast_from_field(vm, source_file, object, "bases", "ClassDef")?;
let keywords =
KeywordArguments::ast_from_field(vm, source_file, object, "keywords", "ClassDef")?;
let body: Vec<Option<ast::Stmt>> =
get_node_list_field(vm, source_file, object, "body", "ClassDef")?;
let decorator_list: Vec<Option<ast::Decorator>> =
get_node_list_field(vm, source_file, object, "decorator_list", "ClassDef")?;
let runtime_decorator_exprs = runtime_decorator_expr_list(&decorator_list);
let runtime_body = runtime_stmt_list_metadata(&body);
let runtime_decorator_list = runtime_expr_list_metadata(&runtime_decorator_exprs);
let body = lower_runtime_stmt_list(body);
let decorator_list = lower_runtime_decorator_list(decorator_list);
let type_params = type_params_from_field(vm, source_file, object, "type_params", "ClassDef")?;
Ok(ast::StmtClassDef {
node_index: Default::default(),
name,
arguments: merge_class_def_args(Some(bases), Some(keywords)),
body,
decorator_list: decorator_list.into(),
type_params,
range,
runtime_decorator_list,
runtime_body,
})
}
impl Node for ast::StmtClassDef {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
name,
arguments,
body,
decorator_list,
type_params,
range,
runtime_decorator_list,
runtime_body,
} = self;
let (bases, keywords) = split_class_def_args(arguments);
let range =
definition_range_from_name(source_file, name.range.start(), range.end(), "class");
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtClassDef::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("name", name.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item(
"bases",
bases.map_or_else(
|| vm.ctx.new_list(vec![]).into(),
|b| b.ast_to_object(vm, source_file),
),
vm,
)
.unwrap();
dict.set_item(
"keywords",
keywords.map_or_else(
|| vm.ctx.new_list(vec![]).into(),
|k| k.ast_to_object(vm, source_file),
),
vm,
)
.unwrap();
let body = runtime_body.map_or_else(
|| body.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("body", body, vm).unwrap();
dict.set_item(
"decorator_list",
runtime_decorator_list.map_or_else(
|| decorator_list.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
),
vm,
)
.unwrap();
dict.set_item(
"type_params",
type_params.map_or_else(
|| vm.ctx.new_list(vec![]).into(),
|tp| tp.ast_to_object(vm, source_file),
),
vm,
)
.unwrap();
node_add_location(&dict, range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "ClassDef")?;
stmt_class_def_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_return_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtReturn> {
Ok(ast::StmtReturn {
node_index: Default::default(),
value: get_node_field_opt(vm, object, "value")?
.map(|obj| Node::ast_from_object(vm, source_file, obj))
.transpose()?,
range,
})
}
impl Node for ast::StmtReturn {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
value,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtReturn::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("value", value.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Return")?;
stmt_return_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_delete_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtDelete> {
let targets: Vec<Option<ast::Expr>> =
get_node_list_field(vm, source_file, object, "targets", "Delete")?;
let (runtime_targets, targets) = runtime_expr_list_from_values(targets);
Ok(ast::StmtDelete {
node_index: Default::default(),
targets,
range,
runtime_targets,
})
}
impl Node for ast::StmtDelete {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
targets,
range: _range,
runtime_targets,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtDelete::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
let targets = runtime_targets.map_or_else(
|| targets.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("targets", targets, vm).unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Delete")?;
stmt_delete_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_assign_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtAssign> {
let targets: Vec<Option<ast::Expr>> =
get_node_list_field(vm, source_file, object, "targets", "Assign")?;
let (runtime_targets, targets) = runtime_expr_list_from_values(targets);
let value = get_required_node_field(vm, source_file, object, "value", "Assign")?;
let (runtime_type_comment, runtime_type_comment_bytes) =
runtime_stmt_type_comment(vm, get_ast_string_field_opt(vm, object, "type_comment")?);
Ok(ast::StmtAssign {
node_index: Default::default(),
targets,
value,
range,
runtime_targets,
runtime_type_comment,
runtime_type_comment_bytes,
})
}
impl Node for ast::StmtAssign {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
targets,
value,
range,
runtime_targets,
runtime_type_comment,
runtime_type_comment_bytes,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtAssign::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
let targets = runtime_targets.map_or_else(
|| targets.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("targets", targets, vm).unwrap();
dict.set_item("value", value.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item(
"type_comment",
runtime_stmt_type_comment_object(vm, runtime_type_comment, runtime_type_comment_bytes),
vm,
)
.unwrap();
node_add_location(&dict, range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &object, "Assign")?;
stmt_assign_from_object_with_range(vm, source_file, &object, range)
}
}
fn stmt_type_alias_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtTypeAlias> {
Ok(ast::StmtTypeAlias {
node_index: Default::default(),
name: get_required_node_field(vm, source_file, object, "name", "TypeAlias")?,
type_params: type_params_from_field(vm, source_file, object, "type_params", "TypeAlias")?,
value: get_required_node_field(vm, source_file, object, "value", "TypeAlias")?,
range,
})
}
impl Node for ast::StmtTypeAlias {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
name,
type_params,
value,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtTypeAlias::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("name", name.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item(
"type_params",
type_params.map_or_else(
|| vm.ctx.new_list(Vec::new()).into(),
|tp| tp.ast_to_object(vm, source_file),
),
vm,
)
.unwrap();
dict.set_item("value", value.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "TypeAlias")?;
stmt_type_alias_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_aug_assign_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtAugAssign> {
Ok(ast::StmtAugAssign {
node_index: Default::default(),
target: get_required_node_field(vm, source_file, object, "target", "AugAssign")?,
op: Node::ast_from_object(
vm,
source_file,
get_node_field_required(vm, object, "op", "AugAssign")?,
)?,
value: get_required_node_field(vm, source_file, object, "value", "AugAssign")?,
range,
})
}
impl Node for ast::StmtAugAssign {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
target,
op,
value,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtAugAssign::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("target", target.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("op", op.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("value", value.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "AugAssign")?;
stmt_aug_assign_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_ann_assign_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtAnnAssign> {
let simple_obj = get_node_field(vm, object, "simple", "AnnAssign")?;
let simple = node_object_to_i32(vm, &simple_obj)?;
let runtime_simple = if simple != 0 && simple != 1 {
Some(simple)
} else {
None
};
Ok(ast::StmtAnnAssign {
node_index: Default::default(),
target: get_required_node_field(vm, source_file, object, "target", "AnnAssign")?,
annotation: get_required_node_field(vm, source_file, object, "annotation", "AnnAssign")?,
value: get_node_field_opt(vm, object, "value")?
.map(|obj| Node::ast_from_object(vm, source_file, obj))
.transpose()?,
simple: simple != 0,
range,
runtime_simple,
})
}
impl Node for ast::StmtAnnAssign {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
target,
annotation,
value,
simple,
range: _range,
runtime_simple,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtAnnAssign::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("target", target.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("annotation", annotation.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("value", value.ast_to_object(vm, source_file), vm)
.unwrap();
let simple = runtime_simple.map_or_else(
|| simple.ast_to_object(vm, source_file),
|simple| vm.ctx.new_int(simple).into(),
);
dict.set_item("simple", simple, vm).unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "AnnAssign")?;
stmt_ann_assign_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_for_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
is_async: bool,
) -> PyResult<ast::StmtFor> {
let typ = if is_async { "AsyncFor" } else { "For" };
let target = get_required_node_field(vm, source_file, object, "target", typ)?;
let iter = get_required_node_field(vm, source_file, object, "iter", typ)?;
let body: Vec<Option<ast::Stmt>> = get_node_list_field(vm, source_file, object, "body", typ)?;
let orelse: Vec<Option<ast::Stmt>> =
get_node_list_field(vm, source_file, object, "orelse", typ)?;
let runtime_body = runtime_stmt_list_metadata(&body);
let runtime_orelse = runtime_stmt_list_metadata(&orelse);
let body = lower_runtime_stmt_list(body);
let orelse = lower_runtime_stmt_list(orelse);
let (runtime_type_comment, runtime_type_comment_bytes) =
runtime_stmt_type_comment(vm, get_ast_string_field_opt(vm, object, "type_comment")?);
Ok(ast::StmtFor {
node_index: Default::default(),
target,
iter,
body,
orelse,
range,
is_async,
runtime_type_comment,
runtime_type_comment_bytes,
runtime_body,
runtime_orelse,
})
}
impl Node for ast::StmtFor {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
is_async,
target,
iter,
body,
orelse,
range: _range,
runtime_type_comment,
runtime_type_comment_bytes,
runtime_body,
runtime_orelse,
} = self;
let cls = if !is_async {
pyast::NodeStmtFor::static_type().to_owned()
} else {
pyast::NodeStmtAsyncFor::static_type().to_owned()
};
let node = NodeAst.into_ref_with_type(vm, cls).unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("target", target.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("iter", iter.ast_to_object(vm, source_file), vm)
.unwrap();
let body = runtime_body.map_or_else(
|| body.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("body", body, vm).unwrap();
let orelse = runtime_orelse.map_or_else(
|| orelse.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("orelse", orelse, vm).unwrap();
dict.set_item(
"type_comment",
runtime_stmt_type_comment_object(vm, runtime_type_comment, runtime_type_comment_bytes),
vm,
)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
debug_assert!(
is_node_instance(vm, &_object, pyast::NodeStmtFor::static_type())?
|| is_node_instance(vm, &_object, pyast::NodeStmtAsyncFor::static_type())?
);
let is_async = is_node_instance(vm, &_object, pyast::NodeStmtAsyncFor::static_type())?;
let typ = if is_async { "AsyncFor" } else { "For" };
let range = range_from_object(vm, source_file, &_object, typ)?;
stmt_for_from_object_with_range(vm, source_file, &_object, range, is_async)
}
}
fn stmt_while_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtWhile> {
let body: Vec<Option<ast::Stmt>> =
get_node_list_field(vm, source_file, object, "body", "While")?;
let orelse: Vec<Option<ast::Stmt>> =
get_node_list_field(vm, source_file, object, "orelse", "While")?;
let runtime_body = runtime_stmt_list_metadata(&body);
let runtime_orelse = runtime_stmt_list_metadata(&orelse);
Ok(ast::StmtWhile {
node_index: Default::default(),
test: get_required_node_field(vm, source_file, object, "test", "While")?,
body: lower_runtime_stmt_list(body),
orelse: lower_runtime_stmt_list(orelse),
range,
runtime_body,
runtime_orelse,
})
}
impl Node for ast::StmtWhile {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
test,
body,
orelse,
range: _range,
runtime_body,
runtime_orelse,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtWhile::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("test", test.ast_to_object(vm, source_file), vm)
.unwrap();
let body = runtime_body.map_or_else(
|| body.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("body", body, vm).unwrap();
let orelse = runtime_orelse.map_or_else(
|| orelse.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("orelse", orelse, vm).unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "While")?;
stmt_while_from_object_with_range(vm, source_file, &_object, range)
}
}
impl Node for ast::StmtIf {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index,
test,
body,
range,
elif_else_clauses,
runtime_body,
} = self;
elif_else_clause::ast_to_object(
ast::ElifElseClause {
node_index,
range,
test: Some(*test),
body,
runtime_body,
runtime_orelse: None,
},
elif_else_clauses.into_iter(),
vm,
source_file,
)
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &object, "If")?;
elif_else_clause::ast_from_object_with_range(vm, source_file, &object, range)
}
}
fn stmt_with_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
is_async: bool,
) -> PyResult<ast::StmtWith> {
let typ = if is_async { "AsyncWith" } else { "With" };
let items = get_node_list_field(vm, source_file, object, "items", typ)?;
let body: Vec<Option<ast::Stmt>> = get_node_list_field(vm, source_file, object, "body", typ)?;
let (runtime_body, body) = runtime_stmt_list_from_values(body);
let (runtime_type_comment, runtime_type_comment_bytes) =
runtime_stmt_type_comment(vm, get_ast_string_field_opt(vm, object, "type_comment")?);
Ok(ast::StmtWith {
node_index: Default::default(),
items,
body,
range,
is_async,
runtime_type_comment,
runtime_type_comment_bytes,
runtime_body,
})
}
impl Node for ast::StmtWith {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
is_async,
items,
body,
range: _range,
runtime_type_comment,
runtime_type_comment_bytes,
runtime_body,
} = self;
let cls = if !is_async {
pyast::NodeStmtWith::static_type().to_owned()
} else {
pyast::NodeStmtAsyncWith::static_type().to_owned()
};
let node = NodeAst.into_ref_with_type(vm, cls).unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("items", items.ast_to_object(vm, source_file), vm)
.unwrap();
let body = runtime_body.map_or_else(
|| body.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("body", body, vm).unwrap();
dict.set_item(
"type_comment",
runtime_stmt_type_comment_object(vm, runtime_type_comment, runtime_type_comment_bytes),
vm,
)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
debug_assert!(
is_node_instance(vm, &_object, pyast::NodeStmtWith::static_type())?
|| is_node_instance(vm, &_object, pyast::NodeStmtAsyncWith::static_type())?
);
let is_async = is_node_instance(vm, &_object, pyast::NodeStmtAsyncWith::static_type())?;
let typ = if is_async { "AsyncWith" } else { "With" };
let range = range_from_object(vm, source_file, &_object, typ)?;
stmt_with_from_object_with_range(vm, source_file, &_object, range, is_async)
}
}
fn stmt_match_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtMatch> {
Ok(ast::StmtMatch {
node_index: Default::default(),
subject: get_required_node_field(vm, source_file, object, "subject", "Match")?,
cases: get_node_list_field(vm, source_file, object, "cases", "Match")?,
range,
})
}
impl Node for ast::StmtMatch {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
subject,
cases,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtMatch::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("subject", subject.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("cases", cases.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Match")?;
stmt_match_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_raise_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtRaise> {
Ok(ast::StmtRaise {
node_index: Default::default(),
exc: get_node_field_opt(vm, object, "exc")?
.map(|obj| Node::ast_from_object(vm, source_file, obj))
.transpose()?,
cause: get_node_field_opt(vm, object, "cause")?
.map(|obj| Node::ast_from_object(vm, source_file, obj))
.transpose()?,
range,
})
}
impl Node for ast::StmtRaise {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
exc,
cause,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtRaise::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("exc", exc.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("cause", cause.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Raise")?;
stmt_raise_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_try_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
is_star: bool,
) -> PyResult<ast::StmtTry> {
let typ = if is_star { "TryStar" } else { "Try" };
let body: Vec<Option<ast::Stmt>> = get_node_list_field(vm, source_file, object, "body", typ)?;
let orelse: Vec<Option<ast::Stmt>> =
get_node_list_field(vm, source_file, object, "orelse", typ)?;
let finalbody: Vec<Option<ast::Stmt>> =
get_node_list_field(vm, source_file, object, "finalbody", typ)?;
let (runtime_handler_values, handlers) =
except_handler_list_from_field(vm, source_file, object, typ, is_star, range)?;
let runtime_body = runtime_stmt_list_metadata(&body);
let runtime_orelse = runtime_stmt_list_metadata(&orelse);
let runtime_finalbody = runtime_stmt_list_metadata(&finalbody);
let runtime_handlers = runtime_except_handler_list_metadata(&runtime_handler_values);
Ok(ast::StmtTry {
node_index: Default::default(),
body: lower_runtime_stmt_list(body),
handlers,
orelse: lower_runtime_stmt_list(orelse),
finalbody: lower_runtime_stmt_list(finalbody),
range,
is_star,
runtime_body,
runtime_handlers,
runtime_orelse,
runtime_finalbody,
})
}
fn except_handler_list_from_field(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
typ: &str,
is_try_star: bool,
range: TextRange,
) -> PyResult<(Vec<Option<ast::ExceptHandler>>, Vec<ast::ExceptHandler>)> {
let value = get_node_list_field_object(vm, object, "handlers", typ)?;
let list = value.downcast_ref::<PyList>().unwrap();
let len = list.borrow_vec().len();
let mut result = Vec::with_capacity(len);
let mut runtime_values = Vec::with_capacity(len);
let recursion_context = format!(" while traversing '{typ}' node");
for i in 0..len {
let item = {
let items = list.borrow_vec();
if items.len() != len {
return Err(vm.new_runtime_error(format!(
r#"{typ} field "handlers" changed size during iteration"#
)));
}
items[i].clone()
};
let runtime_handler = if vm.is_none(&item) {
None
} else {
Some(vm.with_recursion(&recursion_context, || {
if is_try_star {
except_handler_from_object_unvalidated_range(vm, source_file, &item)
} else {
Node::ast_from_object(vm, source_file, item)
}
})?)
};
let handler = runtime_handler.clone().unwrap_or_else(|| {
ast::ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
node_index: Default::default(),
range,
type_: None,
name: None,
body: Vec::new().into(),
runtime_body: None,
})
});
runtime_values.push(runtime_handler);
result.push(handler);
if list.borrow_vec().len() != len {
return Err(vm.new_runtime_error(format!(
r#"{typ} field "handlers" changed size during iteration"#
)));
}
}
Ok((runtime_values, result))
}
impl Node for ast::StmtTry {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
body,
handlers,
orelse,
finalbody,
range: _range,
is_star,
runtime_body,
runtime_handlers,
runtime_orelse,
runtime_finalbody,
} = self;
let cls = if is_star {
pyast::NodeStmtTryStar::static_type()
} else {
pyast::NodeStmtTry::static_type()
}
.to_owned();
let node = NodeAst.into_ref_with_type(vm, cls).unwrap();
let dict = node.as_object().dict().unwrap();
let body = runtime_body.map_or_else(
|| body.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("body", body, vm).unwrap();
let handlers = runtime_handlers.map_or_else(
|| handlers.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("handlers", handlers, vm).unwrap();
let orelse = runtime_orelse.map_or_else(
|| orelse.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("orelse", orelse, vm).unwrap();
let finalbody = runtime_finalbody.map_or_else(
|| finalbody.ast_to_object(vm, source_file),
|values| values.ast_to_object(vm, source_file),
);
dict.set_item("finalbody", finalbody, vm).unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let is_star = is_node_instance(vm, &_object, pyast::NodeStmtTryStar::static_type())?;
debug_assert!(
is_node_instance(vm, &_object, pyast::NodeStmtTry::static_type())?
|| is_node_instance(vm, &_object, pyast::NodeStmtTryStar::static_type())?
);
let typ = if is_star { "TryStar" } else { "Try" };
let range = range_from_object(vm, source_file, &_object, typ)?;
stmt_try_from_object_with_range(vm, source_file, &_object, range, is_star)
}
}
fn stmt_assert_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtAssert> {
Ok(ast::StmtAssert {
node_index: Default::default(),
test: get_required_node_field(vm, source_file, object, "test", "Assert")?,
msg: get_node_field_opt(vm, object, "msg")?
.map(|obj| Node::ast_from_object(vm, source_file, obj))
.transpose()?,
range,
})
}
impl Node for ast::StmtAssert {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
test,
msg,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtAssert::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("test", test.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("msg", msg.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Assert")?;
stmt_assert_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_import_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtImport> {
Ok(ast::StmtImport {
node_index: Default::default(),
names: get_node_list_field(vm, source_file, object, "names", "Import")?,
range,
is_lazy: false,
})
}
impl Node for ast::StmtImport {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
names,
range: _range,
is_lazy: _,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtImport::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("names", names.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Import")?;
stmt_import_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_import_from_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtImportFrom> {
let (level, raw_level) = import_from_level_from_field(vm, object)?;
let runtime_level = raw_level.filter(|level| *level < 0);
Ok(ast::StmtImportFrom {
node_index: Default::default(),
module: get_node_field_opt(vm, object, "module")?
.map(|obj| Node::ast_from_object(vm, source_file, obj))
.transpose()?,
names: get_node_list_field(vm, source_file, object, "names", "ImportFrom")?,
level,
range,
is_lazy: false,
runtime_level,
})
}
fn import_from_level_from_field(
vm: &VirtualMachine,
object: &PyObject,
) -> PyResult<(u32, Option<i32>)> {
let Some(value) = get_node_field_opt(vm, object, "level")? else {
return Ok((0, None));
};
let level = vm.with_recursion(" while traversing 'ImportFrom' node", || {
node_object_to_i32(vm, &value)
})?;
if level < 0 {
return Ok((0, Some(level)));
}
Ok((level as u32, None))
}
impl Node for ast::StmtImportFrom {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
module,
names,
level,
range,
is_lazy: _,
runtime_level,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtImportFrom::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("module", module.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("names", names.ast_to_object(vm, source_file), vm)
.unwrap();
let level = runtime_level.map_or_else(
|| vm.ctx.new_int(level).to_pyobject(vm),
|level| vm.ctx.new_int(level).to_pyobject(vm),
);
dict.set_item("level", level, vm).unwrap();
node_add_location(&dict, range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "ImportFrom")?;
stmt_import_from_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_global_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtGlobal> {
Ok(ast::StmtGlobal {
node_index: Default::default(),
names: get_node_list_field(vm, source_file, object, "names", "Global")?,
range,
})
}
impl Node for ast::StmtGlobal {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
names,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtGlobal::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("names", names.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Global")?;
stmt_global_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_nonlocal_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtNonlocal> {
Ok(ast::StmtNonlocal {
node_index: Default::default(),
names: get_node_list_field(vm, source_file, object, "names", "Nonlocal")?,
range,
})
}
impl Node for ast::StmtNonlocal {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
names,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtNonlocal::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("names", names.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Nonlocal")?;
stmt_nonlocal_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_expr_from_object_with_range(
vm: &VirtualMachine,
source_file: &SourceFile,
object: &PyObject,
range: TextRange,
) -> PyResult<ast::StmtExpr> {
Ok(ast::StmtExpr {
node_index: Default::default(),
value: get_required_node_field(vm, source_file, object, "value", "Expr")?,
range,
})
}
impl Node for ast::StmtExpr {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
value,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtExpr::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("value", value.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Expr")?;
stmt_expr_from_object_with_range(vm, source_file, &_object, range)
}
}
fn stmt_pass_from_object_with_range(range: TextRange) -> ast::StmtPass {
ast::StmtPass {
node_index: Default::default(),
range,
}
}
impl Node for ast::StmtPass {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtPass::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
let location = super::text_range_to_source_range(source_file, _range);
let start_row = location.start.row.get();
let start_col = location.start.column.get();
let mut end_row = location.end.row.get();
let end_col = if end_row != start_row && _range.len() == TextSize::from(4) {
end_row = start_row;
start_col + 4
} else {
location.end.column.get()
};
dict.set_item("lineno", vm.ctx.new_int(start_row).into(), vm)
.unwrap();
dict.set_item("col_offset", vm.ctx.new_int(start_col).into(), vm)
.unwrap();
dict.set_item("end_lineno", vm.ctx.new_int(end_row).into(), vm)
.unwrap();
dict.set_item("end_col_offset", vm.ctx.new_int(end_col).into(), vm)
.unwrap();
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Pass")?;
Ok(stmt_pass_from_object_with_range(range))
}
}
fn stmt_break_from_object_with_range(range: TextRange) -> ast::StmtBreak {
ast::StmtBreak {
node_index: Default::default(),
range,
}
}
impl Node for ast::StmtBreak {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtBreak::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Break")?;
Ok(stmt_break_from_object_with_range(range))
}
}
fn stmt_continue_from_object_with_range(range: TextRange) -> ast::StmtContinue {
ast::StmtContinue {
node_index: Default::default(),
range,
}
}
impl Node for ast::StmtContinue {
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
let Self {
node_index: _,
range: _range,
} = self;
let node = NodeAst
.into_ref_with_type(vm, pyast::NodeStmtContinue::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
node_add_location(&dict, _range, vm, source_file);
node.into()
}
fn ast_from_object(
vm: &VirtualMachine,
source_file: &SourceFile,
_object: PyObjectRef,
) -> PyResult<Self> {
let range = range_from_object(vm, source_file, &_object, "Continue")?;
Ok(stmt_continue_from_object_with_range(range))
}
}