From b29118b8c33c0c1f28483848d20cd40fdb10110c Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Sat, 6 Jul 2024 13:39:28 -0700 Subject: [PATCH] full-moon 1.0.0 --- Cargo.lock | 34 +--- Cargo.toml | 2 +- selene-lib/Cargo.toml | 7 +- selene-lib/default_std/lua52.yml | 2 + selene-lib/default_std/lua53.yml | 2 + selene-lib/default_std/luau.yml | 2 + selene-lib/src/ast_util/mod.rs | 2 +- selene-lib/src/ast_util/scopes.rs | 16 +- selene-lib/src/ast_util/visit_nodes.rs | 2 +- selene-lib/src/lints/bad_string_escape.rs | 4 +- .../src/lints/high_cyclomatic_complexity.rs | 3 +- selene-lib/src/lints/mismatched_arg_count.rs | 8 +- selene-lib/src/lints/standard_library.rs | 4 +- .../src/lints/unbalanced_assignments.rs | 2 +- .../src/standard_library/lua_versions.rs | 89 ++++++++++ selene-lib/src/standard_library/mod.rs | 26 +++ selene/src/main.rs | 165 +++++++++++------- 17 files changed, 251 insertions(+), 119 deletions(-) create mode 100644 selene-lib/src/standard_library/lua_versions.rs diff --git a/Cargo.lock b/Cargo.lock index 3b8a6f39..4fa2f1a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,12 +82,6 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" - [[package]] name = "bitflags" version = "1.3.2" @@ -357,15 +351,14 @@ dependencies = [ [[package]] name = "full_moon" -version = "0.19.0" +version = "1.0.0-rc.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ef4f8ad0689d3a86bb483650422d72e6f79a37fdc83ed5426cafe96b776ce1" +checksum = "1c23cbff7830f7a5370221b5c073bafc74b5d9e8555873b1f153a41416837e4e" dependencies = [ "bytecount", "cfg-if", "derive_more", "full_moon_derive", - "logos", "paste", "serde", "smol_str", @@ -572,29 +565,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "logos" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1" -dependencies = [ - "logos-derive", -] - -[[package]] -name = "logos-derive" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c" -dependencies = [ - "beef", - "fnv", - "proc-macro2", - "quote", - "regex-syntax", - "syn", -] - [[package]] name = "loom" version = "0.5.6" diff --git a/Cargo.toml b/Cargo.toml index caf6734f..87304bb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ license = "MPL-2.0" repository = "https://github.com/Kampfkarren/selene" [workspace.dependencies] -full_moon = "0.19.0" +full_moon = "1.0.0-rc.5" toml = "0.7.2" # Do not update this without confirming profiling uses the same version of tracy-client as selene diff --git a/selene-lib/Cargo.toml b/selene-lib/Cargo.toml index 96f8ce6e..9dce1936 100644 --- a/selene-lib/Cargo.toml +++ b/selene-lib/Cargo.toml @@ -30,6 +30,11 @@ pretty_assertions = "1.3" termcolor = "1.2" [features] -default = ["roblox"] +default = ["lua52", "lua53", "lua54", "luajit", "roblox"] force_exhaustive_checks = [] + +lua52 = ["full_moon/lua52"] +lua53 = ["full_moon/lua53"] +lua54 = ["full_moon/lua54"] +luajit = ["full_moon/luajit"] roblox = ["full_moon/roblox"] diff --git a/selene-lib/default_std/lua52.yml b/selene-lib/default_std/lua52.yml index 8fae55e8..73eee76c 100644 --- a/selene-lib/default_std/lua52.yml +++ b/selene-lib/default_std/lua52.yml @@ -1,5 +1,7 @@ --- base: lua51 +lua_versions: + - lua52 globals: bit32.arshift: args: diff --git a/selene-lib/default_std/lua53.yml b/selene-lib/default_std/lua53.yml index 528dd2cd..581d3957 100644 --- a/selene-lib/default_std/lua53.yml +++ b/selene-lib/default_std/lua53.yml @@ -1,5 +1,7 @@ --- base: lua52 +lua_versions: + - lua53 globals: math.tointeger: args: diff --git a/selene-lib/default_std/luau.yml b/selene-lib/default_std/luau.yml index 0243c110..2f22d8e9 100644 --- a/selene-lib/default_std/luau.yml +++ b/selene-lib/default_std/luau.yml @@ -3,6 +3,8 @@ # Invalid (put in selene-lib/default_std/roblox_base.yml instead): CFrame.new(), Instance.new(), task.spawn() --- base: lua51 +lua_versions: + - luau globals: bit32.arshift: args: diff --git a/selene-lib/src/ast_util/mod.rs b/selene-lib/src/ast_util/mod.rs index 98690f26..bdaa6e76 100644 --- a/selene-lib/src/ast_util/mod.rs +++ b/selene-lib/src/ast_util/mod.rs @@ -51,7 +51,7 @@ pub fn is_vararg(expression: &ast::Expression) -> bool { if_chain::if_chain! { if let ast::Expression::Symbol(token) = expression; if let tokenizer::TokenType::Symbol { - symbol: tokenizer::Symbol::Ellipse, + symbol: tokenizer::Symbol::Ellipsis, } = token.token().token_type(); then { diff --git a/selene-lib/src/ast_util/scopes.rs b/selene-lib/src/ast_util/scopes.rs index dadcd47e..a0b3f742 100644 --- a/selene-lib/src/ast_util/scopes.rs +++ b/selene-lib/src/ast_util/scopes.rs @@ -339,8 +339,8 @@ impl ScopeVisitor { self.read_expression(rhs); } - ast::Expression::Function((name, _)) => { - self.read_name(name); + ast::Expression::Function(function_box) => { + self.read_name(&function_box.0); } ast::Expression::FunctionCall(call) => { @@ -357,7 +357,7 @@ impl ScopeVisitor { ast::Expression::Symbol(symbol) => { if *symbol.token_type() == (TokenType::Symbol { - symbol: Symbol::Ellipse, + symbol: Symbol::Ellipsis, }) { self.read_name(symbol); @@ -433,7 +433,7 @@ impl ScopeVisitor { if token.token_kind() == TokenKind::Identifier || *token.token_type() == (TokenType::Symbol { - symbol: Symbol::Ellipse, + symbol: Symbol::Ellipsis, }) { self.captured_references.insert(identifier); @@ -878,7 +878,7 @@ impl Visitor for ScopeVisitor { } #[cfg(feature = "roblox")] - fn visit_compound_assignment(&mut self, compound_assignment: &ast::types::CompoundAssignment) { + fn visit_compound_assignment(&mut self, compound_assignment: &ast::luau::CompoundAssignment) { self.read_var(compound_assignment.lhs()); self.read_expression(compound_assignment.rhs()); } @@ -911,7 +911,7 @@ impl Visitor for ScopeVisitor { self.current_scope().blocked.push(Cow::Borrowed("...")); for parameter in body.parameters() { - if let ast::Parameter::Ellipse(token) | ast::Parameter::Name(token) = parameter { + if let ast::Parameter::Ellipsis(token) | ast::Parameter::Name(token) = parameter { self.define_name(token, range(token)); } } @@ -1092,8 +1092,8 @@ impl Visitor for ScopeVisitor { } #[cfg(feature = "roblox")] - fn visit_type_info(&mut self, type_info: &ast::types::TypeInfo) { - if let ast::types::TypeInfo::Module { module, .. } = type_info { + fn visit_type_info(&mut self, type_info: &ast::luau::TypeInfo) { + if let ast::luau::TypeInfo::Module { module, .. } = type_info { self.read_name(module); } } diff --git a/selene-lib/src/ast_util/visit_nodes.rs b/selene-lib/src/ast_util/visit_nodes.rs index 163365ae..d993c15e 100644 --- a/selene-lib/src/ast_util/visit_nodes.rs +++ b/selene-lib/src/ast_util/visit_nodes.rs @@ -1,7 +1,7 @@ use full_moon::{ast::*, node::Node, tokenizer::TokenReference, visitors::Visitor}; #[cfg(feature = "roblox")] -use full_moon::ast::types::*; +use full_moon::ast::luau::*; pub(crate) trait NodeVisitor { fn visit_node(&mut self, node: &dyn Node, visitor_type: VisitorType); diff --git a/selene-lib/src/lints/bad_string_escape.rs b/selene-lib/src/lints/bad_string_escape.rs index dc4284ea..c9226210 100644 --- a/selene-lib/src/lints/bad_string_escape.rs +++ b/selene-lib/src/lints/bad_string_escape.rs @@ -107,8 +107,8 @@ impl Visitor for BadStringEscapeVisitor { fn visit_expression(&mut self, node: &ast::Expression) { if_chain::if_chain! { if let ast::Expression::String(token) = node; - if let tokenizer::TokenType::StringLiteral { literal, multi_line, quote_type } = token.token_type(); - if multi_line.is_none(); + if let tokenizer::TokenType::StringLiteral { literal, quote_type, .. } = token.token_type(); + if *quote_type != tokenizer::StringLiteralQuoteType::Brackets; then { let quote_type = *quote_type; let value_start = node.range().unwrap().0.bytes(); diff --git a/selene-lib/src/lints/high_cyclomatic_complexity.rs b/selene-lib/src/lints/high_cyclomatic_complexity.rs index adee8e28..695fb98a 100644 --- a/selene-lib/src/lints/high_cyclomatic_complexity.rs +++ b/selene-lib/src/lints/high_cyclomatic_complexity.rs @@ -400,7 +400,8 @@ impl Visitor for HighCyclomaticComplexityVisitor { } fn visit_expression(&mut self, expression: &ast::Expression) { - if let ast::Expression::Function((_, function_body)) = expression { + if let ast::Expression::Function(function_box) = expression { + let function_body = &function_box.1; let complexity = count_block_complexity(function_body.block(), 1); if complexity > self.config.maximum_complexity { self.positions.push(( diff --git a/selene-lib/src/lints/mismatched_arg_count.rs b/selene-lib/src/lints/mismatched_arg_count.rs index a22f0c88..a7a606f5 100644 --- a/selene-lib/src/lints/mismatched_arg_count.rs +++ b/selene-lib/src/lints/mismatched_arg_count.rs @@ -107,7 +107,7 @@ impl ParameterCount { )] match parameter { ast::Parameter::Name(_) => necessary_params += 1, - ast::Parameter::Ellipse(_) => { + ast::Parameter::Ellipsis(_) => { if necessary_params == 0 { return Self::Variable; } else { @@ -331,7 +331,8 @@ impl Visitor for MapFunctionDefinitionVisitor<'_> { .zip(local_assignment.expressions()); for (name_token, expression) in assignment_expressions { - if let ast::Expression::Function((_, function_body)) = expression { + if let ast::Expression::Function(function_box) = expression { + let function_body = &function_box.1; let identifier = range(name_token); if let Some(id) = self.find_variable(identifier) { @@ -346,7 +347,8 @@ impl Visitor for MapFunctionDefinitionVisitor<'_> { let assignment_expressions = assignment.variables().iter().zip(assignment.expressions()); for (var, expression) in assignment_expressions { - if let ast::Expression::Function((_, function_body)) = expression { + if let ast::Expression::Function(function_box) = expression { + let function_body = &function_box.1; let identifier = range(var); if let Some(reference) = self.find_reference(identifier) { diff --git a/selene-lib/src/lints/standard_library.rs b/selene-lib/src/lints/standard_library.rs index 6c4942c6..4ccdc2ac 100644 --- a/selene-lib/src/lints/standard_library.rs +++ b/selene-lib/src/lints/standard_library.rs @@ -76,7 +76,7 @@ fn get_argument_type(expression: &ast::Expression) -> Option Symbol::False => Some(ArgumentType::Bool.into()), Symbol::True => Some(ArgumentType::Bool.into()), Symbol::Nil => Some(ArgumentType::Nil.into()), - Symbol::Ellipse => Some(ArgumentType::Vararg.into()), + Symbol::Ellipsis => Some(ArgumentType::Vararg.into()), ref other => { unreachable!("TokenType::Symbol was not expected ({:?})", other) } @@ -532,7 +532,7 @@ impl Visitor for StandardLibraryVisitor<'_> { ast::Expression::Symbol(token_ref) => { if let TokenType::Symbol { symbol } = token_ref.token().token_type() { - if symbol == &full_moon::tokenizer::Symbol::Ellipse { + if symbol == &full_moon::tokenizer::Symbol::Ellipsis { maybe_more_arguments = true; } } diff --git a/selene-lib/src/lints/unbalanced_assignments.rs b/selene-lib/src/lints/unbalanced_assignments.rs index df1db4b2..e88f046a 100644 --- a/selene-lib/src/lints/unbalanced_assignments.rs +++ b/selene-lib/src/lints/unbalanced_assignments.rs @@ -94,7 +94,7 @@ fn expression_is_ellipsis(expression: &ast::Expression) -> bool { if let ast::Expression::Symbol(symbol) = expression { return *symbol.token_type() == TokenType::Symbol { - symbol: Symbol::Ellipse, + symbol: Symbol::Ellipsis, }; } diff --git a/selene-lib/src/standard_library/lua_versions.rs b/selene-lib/src/standard_library/lua_versions.rs new file mode 100644 index 00000000..6b1a6c5c --- /dev/null +++ b/selene-lib/src/standard_library/lua_versions.rs @@ -0,0 +1,89 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum LuaVersion { + Lua51, + Lua52, + Lua53, + Lua54, + Luau, + LuaJIT, + + Unknown(String), +} + +impl LuaVersion { + pub fn from_str(value: &str) -> Self { + match value { + "lua51" => Self::Lua51, + "lua52" => Self::Lua52, + "lua53" => Self::Lua53, + "lua54" => Self::Lua54, + "luau" => Self::Luau, + "luajit" => Self::LuaJIT, + _ => Self::Unknown(value.to_string()), + } + } + + pub fn to_str(&self) -> &str { + match self { + Self::Lua51 => "lua51", + Self::Lua52 => "lua52", + Self::Lua53 => "lua53", + Self::Lua54 => "lua54", + Self::Luau => "luau", + Self::LuaJIT => "luajit", + Self::Unknown(value) => value, + } + } + + pub fn to_lua_version(&self) -> Result { + match self { + Self::Lua51 => Ok(full_moon::ast::LuaVersion::lua51()), + + #[cfg(feature = "lua52")] + Self::Lua52 => Ok(full_moon::ast::LuaVersion::lua52()), + + #[cfg(feature = "lua53")] + Self::Lua53 => Ok(full_moon::ast::LuaVersion::lua53()), + + #[cfg(feature = "lua54")] + Self::Lua54 => Ok(full_moon::ast::LuaVersion::lua54()), + + #[cfg(feature = "roblox")] + Self::Luau => Ok(full_moon::ast::LuaVersion::luau()), + + #[cfg(feature = "luajit")] + Self::LuaJIT => Ok(full_moon::ast::LuaVersion::luajit()), + + Self::Unknown(value) => Err(LuaVersionError::Unknown(value)), + + #[allow(unreachable_patterns)] + _ => Err(LuaVersionError::FeatureNotEnabled(self.to_str())), + } + } +} + +pub enum LuaVersionError<'a> { + FeatureNotEnabled(&'a str), + Unknown(&'a str), +} + +impl Serialize for LuaVersion { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(self.to_str()) + } +} + +impl<'de> Deserialize<'de> for LuaVersion { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let value = String::deserialize(deserializer)?; + Ok(Self::from_str(&value)) + } +} diff --git a/selene-lib/src/standard_library/mod.rs b/selene-lib/src/standard_library/mod.rs index 79ff08f5..1ad9cee5 100644 --- a/selene-lib/src/standard_library/mod.rs +++ b/selene-lib/src/standard_library/mod.rs @@ -1,3 +1,4 @@ +mod lua_versions; pub mod v1; mod v1_upgrade; @@ -15,6 +16,8 @@ use serde::{ Deserialize, Serialize, }; +pub use lua_versions::*; + lazy_static::lazy_static! { static ref ANY_TABLE: BTreeMap = { let mut map = BTreeMap::new(); @@ -117,6 +120,9 @@ pub struct StandardLibrary { #[serde(skip_serializing_if = "BTreeMap::is_empty")] pub structs: BTreeMap>, + #[serde(default)] + pub lua_versions: Vec, + /// Internal, used for the Roblox standard library #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] @@ -314,6 +320,11 @@ impl StandardLibrary { }), ); + // Intentionally not a merge, didn't seem valuable + if !other.lua_versions.is_empty() { + self.lua_versions = other.lua_versions; + } + self.globals = globals; } @@ -339,6 +350,21 @@ impl StandardLibrary { Some(std) } + + pub fn lua_version(&self) -> (full_moon::LuaVersion, Vec) { + let mut errors = Vec::new(); + + let mut lua_version = full_moon::LuaVersion::lua51(); + + for version in &self.lua_versions { + match version.to_lua_version() { + Ok(version) => lua_version |= version, + Err(error) => errors.push(error), + } + } + + (lua_version, errors) + } } macro_rules! names { diff --git a/selene/src/main.rs b/selene/src/main.rs index 610aeb8a..3e67e471 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -15,7 +15,8 @@ use codespan_reporting::{ }, term::DisplayStyle as CodespanDisplayStyle, }; -use selene_lib::{lints::Severity, *}; +use full_moon::LuaVersion; +use selene_lib::{lints::Severity, standard_library::LuaVersionError, *}; use structopt::{clap, StructOpt}; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use threadpool::ThreadPool; @@ -52,6 +53,7 @@ lazy_static::lazy_static! { static LINT_ERRORS: AtomicUsize = AtomicUsize::new(0); static LINT_WARNINGS: AtomicUsize = AtomicUsize::new(0); static PARSE_ERRORS: AtomicUsize = AtomicUsize::new(0); +static STANDARD_LIBRARY_ERRORS: AtomicUsize = AtomicUsize::new(0); fn get_color() -> ColorChoice { let lock = OPTIONS.read().unwrap(); @@ -178,7 +180,12 @@ fn emit_codespan_locked( emit_codespan(&mut stdout, files, diagnostic); } -fn read(checker: &Checker, filename: &Path, mut reader: R) { +fn read( + checker: &Checker, + filename: &Path, + lua_version: LuaVersion, + mut reader: R, +) { let mut buffer = Vec::new(); if let Err(error) = reader.read_to_end(&mut buffer) { error!( @@ -202,67 +209,75 @@ fn read(checker: &Checker, filename: &Path, mut rea let ast = { profiling::scope!("full_moon::parse"); - match full_moon::parse(&contents) { + match full_moon::parse_fallible(&contents, lua_version).into_result() { Ok(ast) => ast, - Err(error) => { - PARSE_ERRORS.fetch_add(1, Ordering::SeqCst); - - match error { - full_moon::Error::AstError(full_moon::ast::AstError::UnexpectedToken { - token, - additional, - }) => emit_codespan_locked( - &files, - &CodespanDiagnostic { - severity: CodespanSeverity::Error, - code: Some("parse_error".to_owned()), - message: format!("unexpected token `{token}`"), - labels: vec![CodespanLabel::primary( - source_id, - codespan::Span::new( - token.start_position().bytes() as u32, - token.end_position().bytes() as u32, - ), + Err(errors) => { + for error in errors { + PARSE_ERRORS.fetch_add(1, Ordering::SeqCst); + match error { + full_moon::Error::AstError(ast_error) => { + let token = ast_error.token(); + + emit_codespan_locked( + &files, + &CodespanDiagnostic { + severity: CodespanSeverity::Error, + code: Some("parse_error".to_owned()), + message: format!("unexpected token `{token}`"), + labels: vec![CodespanLabel::primary( + source_id, + codespan::Span::new( + token.start_position().bytes() as u32, + token.end_position().bytes() as u32, + ), + ) + .with_message(ast_error.error_message())], + notes: Vec::new(), + }, ) - .with_message(additional.unwrap_or_default())], - notes: Vec::new(), - }, - ), - full_moon::Error::TokenizerError(error) => emit_codespan_locked( - &files, - &CodespanDiagnostic { - severity: CodespanSeverity::Error, - code: Some("parse_error".to_owned()), - message: match error.error() { - full_moon::tokenizer::TokenizerErrorType::UnclosedComment => { - "unclosed comment".to_string() - } - full_moon::tokenizer::TokenizerErrorType::UnclosedString => { - "unclosed string".to_string() - } - full_moon::tokenizer::TokenizerErrorType::UnexpectedShebang => { - "unexpected shebang".to_string() - } - full_moon::tokenizer::TokenizerErrorType::UnexpectedToken( - character, - ) => { - format!("unexpected character {character}") - } - full_moon::tokenizer::TokenizerErrorType::InvalidSymbol(symbol) => { - format!("invalid symbol {symbol}") - } + } + + full_moon::Error::TokenizerError(error) => emit_codespan_locked( + &files, + &CodespanDiagnostic { + severity: CodespanSeverity::Error, + code: Some("parse_error".to_owned()), + message: match error.error() { + full_moon::tokenizer::TokenizerErrorType::UnclosedComment => { + "unclosed comment".to_string() + } + + full_moon::tokenizer::TokenizerErrorType::UnclosedString => { + "unclosed string".to_string() + } + + full_moon::tokenizer::TokenizerErrorType::UnexpectedToken( + character, + ) => { + format!("unexpected character {character}") + } + + full_moon::tokenizer::TokenizerErrorType::InvalidNumber => { + "invalid number".to_string() + } + + full_moon::tokenizer::TokenizerErrorType::InvalidSymbol( + symbol, + ) => { + format!("invalid symbol {symbol}") + } + }, + labels: vec![CodespanLabel::primary( + source_id, + codespan::Span::new( + error.position().bytes() as u32, + error.position().bytes() as u32, + ), + )], + notes: Vec::new(), }, - labels: vec![CodespanLabel::primary( - source_id, - codespan::Span::new( - error.position().bytes() as u32, - error.position().bytes() as u32, - ), - )], - notes: Vec::new(), - }, - ), - _ => error!("Error parsing {}: {}", filename.display(), error), + ), + } } return; @@ -376,10 +391,11 @@ fn read(checker: &Checker, filename: &Path, mut rea } } -fn read_file(checker: &Checker, filename: &Path) { +fn read_file(checker: &Checker, lua_version: LuaVersion, filename: &Path) { read( checker, filename, + lua_version, match fs::File::open(filename) { Ok(file) => file, Err(error) => { @@ -595,6 +611,21 @@ fn start(mut options: opts::Options) { } }; + let (lua_version, problems) = standard_library.lua_version(); + if !problems.is_empty() { + for problem in problems { + match problem { + LuaVersionError::FeatureNotEnabled(feature) => { + error!("lua version {feature} in standard library, but feature for it is not enabled"); + } + + LuaVersionError::Unknown(version) => { + error!("unknown lua version {version} in standard library"); + } + } + } + } + let checker = Arc::new(match Checker::new(config, standard_library) { Ok(checker) => checker, Err(error) => { @@ -608,7 +639,7 @@ fn start(mut options: opts::Options) { for filename in &options.files { if filename == "-" { let checker = Arc::clone(&checker); - pool.execute(move || read(&checker, Path::new("-"), io::stdin().lock())); + pool.execute(move || read(&checker, Path::new("-"), lua_version, io::stdin().lock())); continue; } @@ -622,7 +653,7 @@ fn start(mut options: opts::Options) { continue; } - pool.execute(move || read_file(&checker, Path::new(&filename))); + pool.execute(move || read_file(&checker, lua_version, Path::new(&filename))); } else if metadata.is_dir() { for pattern in &options.pattern { let glob = match glob::glob(&format!( @@ -646,7 +677,7 @@ fn start(mut options: opts::Options) { let checker = Arc::clone(&checker); - pool.execute(move || read_file(&checker, &path)); + pool.execute(move || read_file(&checker, lua_version, &path)); } Err(error) => { @@ -678,17 +709,19 @@ fn start(mut options: opts::Options) { pool.join(); - let (parse_errors, lint_errors, lint_warnings) = ( + let (parse_errors, lint_errors, lint_warnings, standard_library_errors) = ( PARSE_ERRORS.load(Ordering::SeqCst), LINT_ERRORS.load(Ordering::SeqCst), LINT_WARNINGS.load(Ordering::SeqCst), + STANDARD_LIBRARY_ERRORS.load(Ordering::SeqCst), ); if !options.luacheck && !options.no_summary { log_total(parse_errors, lint_errors, lint_warnings).ok(); } - let error_count = parse_errors + lint_errors + lint_warnings + pool.panic_count(); + let error_count = + parse_errors + lint_errors + lint_warnings + standard_library_errors + pool.panic_count(); if error_count > 0 { let lock = OPTIONS.read().unwrap(); let opts = lock.as_ref().unwrap();