use bevy::log::trace;
use super::ast::{self, AstRef, FnIndex, Template};
use super::scope::{Arguments, Parameters};
use super::Input;
pub type Span = (u32, u32);
pub type Name<'a> = (&'a [u8], Span);
struct ChirpCall<'t, 'i, 'a> {
input: Input<'i>,
ast: AstRef<'a>,
params: Parameters<'a>,
parent: Option<&'t ChirpCall<'t, 'i, 'a>>,
trailing_methods: ast::Methods<'a>,
trailing_children: ast::Statements<'a>,
}
impl<'t, 'i, 'a> ChirpCall<'t, 'i, 'a> {
fn with_parameters(&'t self, parameters: Parameters<'a>, template: Template<'a>) -> Self {
ChirpCall {
input: self.input,
ast: self.ast,
params: parameters,
trailing_methods: template.methods(),
trailing_children: template.children(),
parent: Some(self),
}
}
fn interpret_template(&self, tpl: Template<'a>, runner: &mut impl Interpreter<'i, 'a>) {
let inp = &self.input;
let (mut name, span) = tpl.name().read_spanned(inp);
name = &name[..name.len() - 1];
let Some(fn_index) = runner.get_template((name, span)) else {
return;
};
let declr = fn_index.get();
let parameters = self.params.scope(declr.parameters(), tpl.arguments(), inp);
let inner_chirp = self.with_parameters(parameters, tpl);
inner_chirp.interpret_root(declr.body(), runner);
}
fn interpret_spawn(&self, spawn: ast::Spawn<'a>, runner: &mut impl Interpreter<'i, 'a>) {
trace!("{} - {spawn:?}", spawn.block_index(self.ast));
let inp = &self.input;
if let Some(name) = spawn.name().get_with_span(inp) {
runner.set_name(name);
}
for method in spawn.methods().iter() {
trace!("{} - {method:?}", method.block_index(self.ast));
let (name, arguments) = (method.name(), method.arguments());
let arguments = Arguments::new(*inp, arguments, &self.params);
runner.method(name.read_spanned(inp), &arguments);
}
let mut no_children = spawn.children().is_empty();
let mut this = self;
loop {
for method in this.trailing_methods.iter() {
trace!("{} - {method:?}", method.block_index(self.ast));
let (name, arguments) = (method.name(), method.arguments());
let empty_parameters = Parameters::empty();
let parameters = this.parent.map_or(&empty_parameters, |p| &p.params);
let arguments = Arguments::new(*inp, arguments, parameters);
runner.method(name.read_spanned(inp), &arguments);
}
no_children &= this.trailing_children.is_empty();
this = match this.parent {
None => break,
Some(v) => v,
};
}
if no_children {
runner.spawn_leaf();
} else {
runner.start_children();
for statement in spawn.children().iter() {
self.file().interpret_statement(statement, runner);
}
let mut this = self;
loop {
for statement in this.trailing_children.iter() {
let root_file = || ChirpFile::new(self.input, self.ast);
let parent = this.parent.map_or_else(root_file, Self::file);
parent.interpret_statement(statement, runner);
}
this = match this.parent {
None => break,
Some(v) => v,
};
}
runner.complete_children();
}
}
fn file(&self) -> ChirpFile<'i, 'a> {
ChirpFile {
input: self.input,
ast: self.ast,
params: self.params.clone(),
}
}
fn interpret_root(&self, statement: ast::Statement<'a>, runner: &mut impl Interpreter<'i, 'a>) {
match statement.typed() {
ast::StType::Template(template) => self.interpret_template(template, runner),
ast::StType::Spawn(spawn) => self.interpret_spawn(spawn, runner),
ast::StType::Code(code) => runner.code(code.name().read_spanned(&self.input)),
}
}
}
pub struct ChirpFile<'i, 'a> {
input: Input<'i>,
ast: AstRef<'a>,
params: Parameters<'a>,
}
impl<'i, 'a> ChirpFile<'i, 'a> {
fn with_parameters(&self, ps: Parameters<'a>, template: Template<'a>) -> ChirpCall<'_, 'i, 'a> {
ChirpCall {
input: self.input,
ast: self.ast,
params: ps,
trailing_methods: template.methods(),
trailing_children: template.children(),
parent: None,
}
}
pub fn new(input: Input<'i>, ast: AstRef<'a>) -> Self {
Self { input, ast, params: Parameters::empty() }
}
fn interpret_spawn(&self, spawn: ast::Spawn<'a>, runner: &mut impl Interpreter<'i, 'a>) {
trace!("{} - {spawn:?}", spawn.block_index(self.ast));
let inp = &self.input;
if let Some(name) = spawn.name().get_with_span(inp) {
runner.set_name(name);
}
for method in spawn.methods().iter() {
trace!("{} - {method:?}", method.block_index(self.ast));
let (name, arguments) = (method.name(), method.arguments());
let arguments = Arguments::new(*inp, arguments, &self.params);
runner.method(name.read_spanned(inp), &arguments);
}
if spawn.children().is_empty() {
runner.spawn_leaf();
} else {
runner.start_children();
for statement in spawn.children().iter() {
self.interpret_statement(statement, runner);
}
runner.complete_children();
}
}
fn interpret_template(&self, tpl: Template<'a>, runner: &mut impl Interpreter<'i, 'a>) {
trace!("{} - {tpl:?}", tpl.block_index(self.ast));
let inp = &self.input;
let (mut name, span) = tpl.name().read_spanned(inp);
name = &name[..name.len() - 1];
let Some(fn_index) = runner.get_template((name, span)) else {
return;
};
let declr = fn_index.get();
let parameters = self.params.scope(declr.parameters(), tpl.arguments(), inp);
let inner_chirp = self.with_parameters(parameters, tpl);
inner_chirp.interpret_root(declr.body(), runner);
}
fn interpret_statement(&self, st: ast::Statement<'a>, runner: &mut impl Interpreter<'i, 'a>) {
match st.typed() {
ast::StType::Template(template) => self.interpret_template(template, runner),
ast::StType::Spawn(spawn) => self.interpret_spawn(spawn, runner),
ast::StType::Code(code) => runner.code(code.name().read_spanned(&self.input)),
}
}
pub fn interpret(&self, runner: &mut impl Interpreter<'i, 'a>) {
let inp = &self.input;
let file = self.ast.chirp_file();
trace!("{} - {file:?}", file.block_index(self.ast));
for import in file.imports().iter() {
trace!("{} - {import:?}", import.block_index(self.ast));
let (name, alias) = (import.name(), import.alias());
runner.import(name.read_spanned(inp), alias.read_spanned(inp));
}
for fn_declr in file.fn_declrs().iter() {
trace!("{} - {fn_declr:?}", fn_declr.block_index(self.ast));
let index = fn_declr.index();
runner.register_fn(fn_declr.name().read_spanned(inp), index);
}
self.interpret_statement(file.root_statement(), runner);
}
}
pub trait Interpreter<'i, 'a> {
fn import(&mut self, name: Name<'i>, alias: Option<Name<'i>>);
fn register_fn(&mut self, name: Name<'i>, index: FnIndex<'a>);
fn get_template(&mut self, name: Name<'i>) -> Option<FnIndex<'a>>;
fn code(&mut self, code: Name<'i>);
fn spawn_leaf(&mut self) {
self.start_children();
self.complete_children();
}
fn set_name(&mut self, name: Name);
fn start_children(&mut self);
fn complete_children(&mut self);
fn method(&mut self, name: Name<'i>, arguments: &Arguments);
}
impl<'a> Interpreter<'_, 'a> for () {
fn code(&mut self, _: Name) {}
fn import(&mut self, _: Name, _: Option<Name>) {}
fn register_fn(&mut self, _: Name, _: FnIndex<'a>) {}
fn get_template(&mut self, _: Name) -> Option<FnIndex<'a>> {
None
}
fn set_name(&mut self, _: Name) {}
fn start_children(&mut self) {}
fn method(&mut self, _: Name, _: &Arguments) {}
fn complete_children(&mut self) {}
}