diff --git a/src/codegen/expr.rs b/src/codegen/expr.rs index f563280..b1da543 100644 --- a/src/codegen/expr.rs +++ b/src/codegen/expr.rs @@ -133,6 +133,15 @@ where T: Write + Seek _span: &Span, opr: &Rrc, ) -> io::Result<()> { + if matches!(op, UnOp::Length) { + if let Expr::Name(Name::Name { name, span: _ }) = &*opr.borrow() { + if s.sprite.lists.contains_key(name) + || s.stage.is_some_and(|stage| stage.lists.contains_key(name)) + { + return self.list_length(this_id, parent_id, name); + } + } + } let opr_id = self.id.new_id(); self.begin_node(Node::new(op.opcode(), this_id).parent_id(parent_id))?; self.begin_inputs()?; @@ -193,4 +202,10 @@ where T: Write + Seek self.end_obj()?; // node self.expr(s, d, &index.borrow(), index_id, this_id) } + + fn list_length(&mut self, this_id: NodeID, parent_id: NodeID, name: &str) -> io::Result<()> { + self.begin_node(Node::new("data_lengthoflist", this_id).parent_id(parent_id))?; + self.single_field_id("LIST", name)?; + self.end_obj() // node + } } diff --git a/src/codegen/sb3.rs b/src/codegen/sb3.rs index 1b0c1f7..4054065 100644 --- a/src/codegen/sb3.rs +++ b/src/codegen/sb3.rs @@ -508,10 +508,9 @@ where T: Write + Seek ) -> io::Result<()> { let data = match &list.cmd { Some(cmd) => { - eprintln!("{cmd:#?}"); let output = Command::new("/usr/bin/sh") .arg("-c") - .arg(format!("cd {};{}", input.display(), cmd.cmd)) + .arg(format!("set -e;cd {};{}", input.display(), cmd.cmd)) .output()?; if !output.status.success() { d.report( diff --git a/src/frontend.rs b/src/frontend.rs index 2415c97..798869d 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -7,51 +7,68 @@ use std::process::ExitCode; use clap::{CommandFactory, Parser}; use cli::{Cli, Command}; use colored::Colorize; +use new::NewError; + +use crate::config::Config; pub fn frontend() -> ExitCode { match Cli::parse().command { - Command::Build { input, output } => { - let result = build::build(input, output); - match result { - Ok(()) => ExitCode::SUCCESS, - Err(build::BuildError::AnyhowError(err)) => { + Command::Build { input, output } => match build::build(input, output) { + Ok(()) => ExitCode::SUCCESS, + Err(build::BuildError::AnyhowError(err)) => { + eprintln!("{}: {:?}", "error".red().bold(), err); + ExitCode::FAILURE + } + Err(build::BuildError::ProjectDiagnostics(diagnostics)) => { + diagnostics.eprint(); + eprintln!(); + ExitCode::FAILURE + } + }, + Command::Completions { shell } => { + shell.generate(&mut Cli::command(), &mut std::io::stdout()); + ExitCode::SUCCESS + } + Command::New { + name, + frame_rate, + max_clones, + no_miscellaneous_limits, + no_sprite_fencing, + frame_interpolation, + high_quality_pen, + stage_width, + stage_height, + } => { + match new::new( + name, + Config { + frame_rate, + max_clones, + no_miscellaneous_limits: Some(no_miscellaneous_limits), + no_sprite_fencing: Some(no_sprite_fencing), + frame_interpolation: Some(frame_interpolation), + high_quality_pen: Some(high_quality_pen), + stage_width, + stage_height, + }, + ) { + Err(NewError::AnyhowError(err)) => { eprintln!("{}: {:?}", "error".red().bold(), err); ExitCode::FAILURE } - Err(build::BuildError::ProjectDiagnostics(diagnostics)) => { - diagnostics.eprint(); - eprintln!(); + Err(NewError::NewDirNotEmpty { + name, + is_name_explicit, + }) => { + eprintln!("{}: {} is not empty", "error".red().bold(), name.display()); + if !is_name_explicit { + eprintln!("{}: use --name to specify a name", "hint".blue().bold()); + } ExitCode::FAILURE } + Ok(_) => ExitCode::SUCCESS, } } - Command::Completions { shell } => { - shell.generate(&mut Cli::command(), &mut std::io::stdout()); - ExitCode::SUCCESS - } - _ => panic!(), - // Command::New { - // name, - // frame_rate, - // max_clones, - // no_miscellaneous_limits, - // no_sprite_fencing, - // frame_interpolation, - // high_quality_pen, - // stage_width, - // stage_height, - // } => new::new( - // name, - // Config { - // frame_rate, - // max_clones, - // no_miscellaneous_limits: Some(no_miscellaneous_limits), - // no_sprite_fencing: Some(no_sprite_fencing), - // frame_interpolation: Some(frame_interpolation), - // high_quality_pen: Some(high_quality_pen), - // stage_width, - // stage_height, - // }, - // ), } } diff --git a/src/frontend/new.rs b/src/frontend/new.rs index 19f2827..8e7f038 100644 --- a/src/frontend/new.rs +++ b/src/frontend/new.rs @@ -1,28 +1,45 @@ -// use std::{env, fs, path::PathBuf}; +use std::{env, fs, path::PathBuf}; -// use anyhow::bail; +use crate::config::Config; -// use crate::config::Config; +pub enum NewError { + AnyhowError(anyhow::Error), + NewDirNotEmpty { + name: PathBuf, + is_name_explicit: bool, + }, +} -// macro_rules! write_templates { -// ($input:expr, $($file:expr),*) => { -// $( -// fs::write($input.join($file), include_str!(concat!("templates/", $file)))?; -// )* -// }; -// } +impl From for NewError +where T: Into +{ + fn from(value: T) -> Self { + Self::AnyhowError(value.into()) + } +} -// pub fn new(name: Option, config: Config) -> anyhow::Result<()> { -// let is_name_explicit = name.is_some(); -// let name = name.unwrap_or_else(|| env::current_dir().unwrap()); -// fs::create_dir(&name)?; -// if name.read_dir()?.count() > 0 { -// return Err(Error::NewDirNotEmpty { name, is_name_explicit }); -// } -// let config_path = name.join("goboscript.toml"); -// if config != Default::default() { -// fs::write(config_path, toml::to_string(&config).unwrap())?; -// } -// write_templates!(name, "stage.gs", "main.gs", "blank.svg"); -// Ok(()) -// } +macro_rules! write_templates { + ($input:expr, $($file:expr),*) => { + $( + fs::write($input.join($file), include_str!(concat!("templates/", $file)))?; + )* + }; +} + +pub fn new(name: Option, config: Config) -> Result<(), NewError> { + let is_name_explicit = name.is_some(); + let name = name.unwrap_or_else(|| env::current_dir().unwrap()); + let _ = fs::create_dir(&name); + if name.read_dir()?.count() > 0 { + return Err(NewError::NewDirNotEmpty { + name, + is_name_explicit, + }); + } + let config_path = name.join("goboscript.toml"); + if config != Default::default() { + fs::write(config_path, toml::to_string(&config).unwrap())?; + } + write_templates!(name, "stage.gs", "main.gs", "blank.svg"); + Ok(()) +}