Fix regression on defined() preprocessing (#152)

Fixes #96.

0a650be853 changed the preprocessor to 
always substitute macros for their value if they were defined, as such 
`#if defined(FOO)` would cause a lint error if `FOO` was defined.

There were two different errors with the exact same message, the first 
would happen if `#define FOO` because `defined()` would have no 
arguments.  The second would happen if `#define FOO 1` because `1` 
isn't an ident.

Because of those tangentially related things I discovered in my 
attempts to fix the bug, I've changed the error messages to be more 
specific.
This commit is contained in:
spookydonut 2020-01-19 06:22:07 +08:00 committed by Tad Hardesty
parent b945de9315
commit bb70113d0f
2 changed files with 18 additions and 6 deletions

View file

@ -743,7 +743,7 @@ impl<'a> ConstantFolder<'a> {
"rgb" => {
use std::fmt::Write;
if args.len() != 3 && args.len() != 4 {
return Err(self.error("malformed rgb() call"));
return Err(self.error(format!("malformed rgb() call, must have 3 or 4 arguments and instead has {}", args.len())));
}
let mut result = String::with_capacity(7);
result.push_str("#");
@ -752,7 +752,7 @@ impl<'a> ConstantFolder<'a> {
let clamped = std::cmp::max(::std::cmp::min(i, 255), 0);
let _ = write!(result, "{:02x}", clamped);
} else {
return Err(self.error("malformed rgb() call"));
return Err(self.error("malformed rgb() call, argument wasn't an int"));
}
}
Constant::String(result)
@ -760,7 +760,7 @@ impl<'a> ConstantFolder<'a> {
"defined" if self.defines.is_some() => {
let defines = self.defines.unwrap(); // annoying, but keeps the match clean
if args.len() != 1 {
return Err(self.error("malformed defined() call"));
return Err(self.error(format!("malformed defined() call, must have 1 argument and instead has {}", args.len())));
}
match args[0] {
Expression::Base {
@ -770,7 +770,7 @@ impl<'a> ConstantFolder<'a> {
} if unary.is_empty() && follow.is_empty() => {
Constant::Int(if defines.contains_key(ident) { 1 } else { 0 })
},
_ => return Err(self.error("malformed defined() call")),
_ => return Err(self.error("malformed defined() call, argument given isn't an Ident.")),
}
}
// other functions are no-goes
@ -789,7 +789,7 @@ impl<'a> ConstantFolder<'a> {
fn trig_op(&mut self, mut args: Vec<Expression>, op: fn(f32) -> f32) -> Result<Constant, DMError> {
if args.len() != 1 {
Err(self.error("trig function requires exactly 1 argument"))
Err(self.error(format!("trig function requires exactly 1 argument, instead found {}", args.len())))
} else if let Some(f) = self.expr(args.remove(0), None)?.to_float() {
Ok(Constant::Float(op(f)))
} else {

View file

@ -930,7 +930,7 @@ impl<'ctx> Preprocessor<'ctx> {
// anything other than directives may be ifdef'd out
_ if disabled => return Ok(()),
// identifiers may be macros
Token::Ident(ref ident, _) => {
Token::Ident(ref ident, whitespace) => {
self.flush_docs();
// lint for BYOND bug
@ -955,6 +955,18 @@ impl<'ctx> Preprocessor<'ctx> {
return Ok(());
}
// special case for inside a defined() call
if let Some(Token::Punct(Punctuation::LParen)) = self.output.back() {
if let Some(idx) = self.output.len().checked_sub(2) {
if let Some(Token::Ident(identname, _)) = self.output.get(idx) {
if identname.as_str() == "defined" {
self.output.push_back(Token::Ident(ident.to_owned(), whitespace));
return Ok(());
}
}
}
}
// if it's a define, perform the substitution
let mut expansion = self.defines.get(ident).cloned(); // TODO: don't clone?
if expansion.is_some() && self.include_stack.stack.len() > MAX_RECURSION_DEPTH {