From fe243e7841410ae5290e2a36621e5b200e62e6e1 Mon Sep 17 00:00:00 2001 From: Mathis Rech Date: Mon, 20 Sep 2021 16:15:39 +0200 Subject: [PATCH 1/4] Add debugger output format --- src/diagn/span.rs | 19 +++++++++++++-- src/driver.rs | 5 +++- src/syntax/token.rs | 8 +++++- src/test/excerpt.rs | 2 +- src/util/bitvec_format.rs | 51 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 5 deletions(-) diff --git a/src/diagn/span.rs b/src/diagn/span.rs index 8be549b1..67a24711 100644 --- a/src/diagn/span.rs +++ b/src/diagn/span.rs @@ -5,17 +5,19 @@ use std::rc::Rc; pub struct Span { pub file: Rc, + pub line: Option, pub location: Option<(usize, usize)> } impl Span { - pub fn new(filename: Rc, start: usize, end: usize) -> Span + pub fn new(filename: Rc, line: usize, start: usize, end: usize) -> Span { Span { file: filename, + line: Some(line), location: Some((start, end)) } } @@ -26,6 +28,7 @@ impl Span Span { file: Rc::new("".to_string()), + line: None, location: None } } @@ -43,6 +46,7 @@ impl Span Span { file: self.file.clone(), + line: self.line, location: Some((start, start)) } } @@ -61,6 +65,7 @@ impl Span Span { file: self.file.clone(), + line: self.line, location: Some((end, end)) } } @@ -84,11 +89,21 @@ impl Span let end = max(self.location.unwrap().1, other.location.unwrap().1); Some((start, end)) }; + + let line = if self.location.unwrap().0 <= other.location.unwrap().0 + { + self.line + } + else + { + other.line + }; Span { file: self.file.clone(), - location: location + line, + location } } } diff --git a/src/driver.rs b/src/driver.rs index 0aa3ef63..dcb306c0 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -19,6 +19,7 @@ enum OutputFormat HexC, LogiSim8, LogiSim16, + Debugger, } @@ -101,6 +102,7 @@ fn drive_inner( Some("c") => OutputFormat::HexC, Some("logisim8") => OutputFormat::LogiSim8, Some("logisim16") => OutputFormat::LogiSim16, + Some("debugger") => OutputFormat::Debugger, None => if out_stdout { OutputFormat::AnnotatedHex } @@ -224,6 +226,7 @@ fn drive_inner( OutputFormat::HexC => binary.format_c_array (16).bytes().collect(), OutputFormat::LogiSim8 => binary.format_logisim (8) .bytes().collect(), OutputFormat::LogiSim16 => binary.format_logisim (16).bytes().collect(), + OutputFormat::Debugger => binary.format_debugger() .bytes().collect(), OutputFormat::AnnotatedHex => binary.format_annotated_hex(fileserver).bytes().collect(), OutputFormat::AnnotatedBin => binary.format_annotated_bin(fileserver).bytes().collect(), @@ -287,7 +290,7 @@ fn drive_inner( fn make_opts() -> getopts::Options { let mut opts = getopts::Options::new(); - opts.optopt("f", "format", "The format of the output file. Possible formats: binary, annotated, annotatedbin, binstr, hexstr, bindump, hexdump, mif, intelhex, deccomma, hexcomma, decc, hexc, logisim8, logisim16", "FORMAT"); + opts.optopt("f", "format", "The format of the output file. Possible formats: binary, annotated, annotatedbin, binstr, hexstr, bindump, hexdump, mif, intelhex, deccomma, hexcomma, decc, hexc, logisim8, logisim16, debugger", "FORMAT"); opts.opt("o", "output", "The name of the output file.", "FILE", getopts::HasArg::Maybe, getopts::Occur::Optional); opts.optopt("", "symbol-format", "The format of the symbol file. Possible formats: default, mesen-mlb", "SYMBOL-FORMAT"); opts.opt("s", "symbol", "The name of the output symbol file.", "FILE", getopts::HasArg::Maybe, getopts::Occur::Optional); diff --git a/src/syntax/token.rs b/src/syntax/token.rs index 43131b51..fa6250d3 100644 --- a/src/syntax/token.rs +++ b/src/syntax/token.rs @@ -243,6 +243,7 @@ where S: Into let filename = Rc::new(src_filename.into()); let mut tokens = Vec::new(); let mut index = 0; + let mut line = 0; let mut had_error = false; while index < src.len() @@ -256,8 +257,13 @@ where S: Into check_for_number (&src[index..]).unwrap_or_else(|| check_for_string (&src[index..]).unwrap_or_else(|| (TokenKind::Error, 1))))))); + + if kind == TokenKind::LineBreak + { + line += 1; + } - let span = Span::new(filename.clone(), index, index + length); + let span = Span::new(filename.clone(), line, index, index + length); // Get the source excerpt for variable tokens (e.g. identifiers). let excerpt = match kind.needs_excerpt() diff --git a/src/test/excerpt.rs b/src/test/excerpt.rs index d447478d..1f02781f 100644 --- a/src/test/excerpt.rs +++ b/src/test/excerpt.rs @@ -16,7 +16,7 @@ fn test(src: &str, expected: ExpectedResult<&str>) let mut fileserver = util::FileServerMock::new(); fileserver.add("test", src_quoted); - let span = diagn::Span::new(Rc::new("test".to_string()), 0, 0); + let span = diagn::Span::new(Rc::new("test".to_string()), 0, 0, 0); let result = syntax::excerpt_as_string_contents(report.clone(), src_quoted, &span).ok(); let result = result.as_ref().map(|s| s.as_ref()); diff --git a/src/util/bitvec_format.rs b/src/util/bitvec_format.rs index 0aa761d1..5f5c42da 100644 --- a/src/util/bitvec_format.rs +++ b/src/util/bitvec_format.rs @@ -476,4 +476,55 @@ impl util::BitVec result } + + pub fn format_debugger(&self) -> String + { + let mut result = String::new(); + + let mut addr_width = 4; + let mut line_width = 4; + + let mut sorted_spans = self.spans.clone(); + sorted_spans.sort_by(|a, b| + { + a.offset.cmp(&b.offset) + }); + + for span in &sorted_spans + { + addr_width = std::cmp::max( + addr_width, + format!("{:x}", span.addr).len()); + + if let Some(line) = span.span.line + { + line_width = std::cmp::max( + line_width, + format!("{}", line).len()); + } + } + + result.push_str(&format!(" {:>1$} |", "addr", addr_width)); + result.push_str(&format!(" {:>1$} | file", "line", line_width)); + result.push_str("\n"); + result.push_str("\n"); + + let mut prev_filename = ""; + + for span in &sorted_spans + { + result.push_str(&format!(" {:1$x} | ", span.addr, addr_width)); + result.push_str(&format!("{:1$} | ", span.span.line.unwrap_or_default(), line_width)); + + if &*span.span.file != prev_filename + { + prev_filename = &*span.span.file; + } + + result.push_str(prev_filename); + result.push_str("\n"); + } + + result + } } \ No newline at end of file From 91c712c0e5cbde9e274765677647a0f32d921988 Mon Sep 17 00:00:00 2001 From: Mathis Rech Date: Mon, 4 Oct 2021 09:53:00 +0200 Subject: [PATCH 2/4] Use CharCounter to find line number --- src/diagn/span.rs | 17 +---------------- src/driver.rs | 2 +- src/syntax/token.rs | 8 +------- src/test/excerpt.rs | 2 +- src/util/bitvec_format.rs | 27 +++++++++++++++++++++++---- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/diagn/span.rs b/src/diagn/span.rs index 67a24711..2be17ae1 100644 --- a/src/diagn/span.rs +++ b/src/diagn/span.rs @@ -5,19 +5,17 @@ use std::rc::Rc; pub struct Span { pub file: Rc, - pub line: Option, pub location: Option<(usize, usize)> } impl Span { - pub fn new(filename: Rc, line: usize, start: usize, end: usize) -> Span + pub fn new(filename: Rc, start: usize, end: usize) -> Span { Span { file: filename, - line: Some(line), location: Some((start, end)) } } @@ -28,7 +26,6 @@ impl Span Span { file: Rc::new("".to_string()), - line: None, location: None } } @@ -46,7 +43,6 @@ impl Span Span { file: self.file.clone(), - line: self.line, location: Some((start, start)) } } @@ -65,7 +61,6 @@ impl Span Span { file: self.file.clone(), - line: self.line, location: Some((end, end)) } } @@ -90,19 +85,9 @@ impl Span Some((start, end)) }; - let line = if self.location.unwrap().0 <= other.location.unwrap().0 - { - self.line - } - else - { - other.line - }; - Span { file: self.file.clone(), - line, location } } diff --git a/src/driver.rs b/src/driver.rs index dcb306c0..68aff91b 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -226,10 +226,10 @@ fn drive_inner( OutputFormat::HexC => binary.format_c_array (16).bytes().collect(), OutputFormat::LogiSim8 => binary.format_logisim (8) .bytes().collect(), OutputFormat::LogiSim16 => binary.format_logisim (16).bytes().collect(), - OutputFormat::Debugger => binary.format_debugger() .bytes().collect(), OutputFormat::AnnotatedHex => binary.format_annotated_hex(fileserver).bytes().collect(), OutputFormat::AnnotatedBin => binary.format_annotated_bin(fileserver).bytes().collect(), + OutputFormat::Debugger => binary.format_debugger (fileserver).bytes().collect(), }; if out_stdout diff --git a/src/syntax/token.rs b/src/syntax/token.rs index fa6250d3..6ed608a5 100644 --- a/src/syntax/token.rs +++ b/src/syntax/token.rs @@ -243,7 +243,6 @@ where S: Into let filename = Rc::new(src_filename.into()); let mut tokens = Vec::new(); let mut index = 0; - let mut line = 0; let mut had_error = false; while index < src.len() @@ -258,12 +257,7 @@ where S: Into check_for_string (&src[index..]).unwrap_or_else(|| (TokenKind::Error, 1))))))); - if kind == TokenKind::LineBreak - { - line += 1; - } - - let span = Span::new(filename.clone(), line, index, index + length); + let span = Span::new(filename.clone(), index, index + length); // Get the source excerpt for variable tokens (e.g. identifiers). let excerpt = match kind.needs_excerpt() diff --git a/src/test/excerpt.rs b/src/test/excerpt.rs index 1f02781f..d447478d 100644 --- a/src/test/excerpt.rs +++ b/src/test/excerpt.rs @@ -16,7 +16,7 @@ fn test(src: &str, expected: ExpectedResult<&str>) let mut fileserver = util::FileServerMock::new(); fileserver.add("test", src_quoted); - let span = diagn::Span::new(Rc::new("test".to_string()), 0, 0, 0); + let span = diagn::Span::new(Rc::new("test".to_string()), 0, 0); let result = syntax::excerpt_as_string_contents(report.clone(), src_quoted, &span).ok(); let result = result.as_ref().map(|s| s.as_ref()); diff --git a/src/util/bitvec_format.rs b/src/util/bitvec_format.rs index 5f5c42da..f0d96183 100644 --- a/src/util/bitvec_format.rs +++ b/src/util/bitvec_format.rs @@ -1,4 +1,6 @@ use crate::*; +use crate::util::CharCounter; +use crate::diagn::RcReport; impl util::BitVec @@ -477,7 +479,7 @@ impl util::BitVec result } - pub fn format_debugger(&self) -> String + pub fn format_debugger(&self, fileserver: &dyn util::FileServer) -> String { let mut result = String::new(); @@ -489,15 +491,19 @@ impl util::BitVec { a.offset.cmp(&b.offset) }); - + for span in &sorted_spans { + let chars = fileserver.get_chars(RcReport::new(), &span.span.file, None).ok().unwrap(); + let counter = CharCounter::new(&chars); + addr_width = std::cmp::max( addr_width, format!("{:x}", span.addr).len()); - if let Some(line) = span.span.line + if let Some((start, _)) = span.span.location { + let (line, _) = counter.get_line_column_at_index(start); line_width = std::cmp::max( line_width, format!("{}", line).len()); @@ -513,8 +519,21 @@ impl util::BitVec for span in &sorted_spans { + let chars = fileserver.get_chars(RcReport::new(), &span.span.file, None).ok().unwrap(); + let counter = CharCounter::new(&chars); + + let line = if let Some((start, _)) = span.span.location + { + let (l, _) = counter.get_line_column_at_index(start); + l + } + else + { + 0 + }; + result.push_str(&format!(" {:1$x} | ", span.addr, addr_width)); - result.push_str(&format!("{:1$} | ", span.span.line.unwrap_or_default(), line_width)); + result.push_str(&format!("{:1$} | ", line, line_width)); if &*span.span.file != prev_filename { From dc014c857daa7e587b8920a223cc8d765dc2a656 Mon Sep 17 00:00:00 2001 From: Mathis Rech Date: Tue, 26 Oct 2021 18:19:41 +0200 Subject: [PATCH 3/4] Implement string encodings --- src/asm/parser/include.rs | 2 +- src/expr/expression.rs | 34 ++++++++++++++++++++++-- src/expr/mod.rs | 1 + src/expr/parser.rs | 10 +++---- src/syntax/parser.rs | 21 +++++++++++++++ src/syntax/token.rs | 56 ++++++++++++++++++++++++++++++++++----- src/test/expr.rs | 21 +++++++++++++++ src/util/bigint.rs | 12 --------- 8 files changed, 130 insertions(+), 27 deletions(-) diff --git a/src/asm/parser/include.rs b/src/asm/parser/include.rs index f090729c..a969cb06 100644 --- a/src/asm/parser/include.rs +++ b/src/asm/parser/include.rs @@ -5,7 +5,7 @@ pub fn parse_directive_include( state: &mut asm::parser::State) -> Result<(), ()> { - let tk_filename = state.parser.expect(syntax::TokenKind::String)?; + let tk_filename = state.parser.expect(syntax::TokenKind::String(expr::StringEncoding::Utf8))?; let filename = syntax::excerpt_as_string_contents( state.report.clone(), tk_filename.excerpt.as_ref().unwrap(), diff --git a/src/expr/expression.rs b/src/expr/expression.rs index 21cdf1a0..26aa7a86 100644 --- a/src/expr/expression.rs +++ b/src/expr/expression.rs @@ -29,11 +29,23 @@ pub enum Value } +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum StringEncoding +{ + Utf8, + Utf16BE, + Utf16LE, + UnicodeBE, + UnicodeLE, + Ascii, +} + + #[derive(Clone, Debug, Eq, PartialEq)] pub struct ValueString { pub utf8_contents: String, - pub encoding: String, + pub encoding: StringEncoding, } @@ -105,6 +117,15 @@ impl Value } + pub fn make_string(s: &str, encoding: expr::StringEncoding) -> Value + { + Value::String(ValueString { + utf8_contents: s.to_string(), + encoding + }) + } + + pub fn get_bigint(&self) -> Option { match self @@ -122,6 +143,15 @@ impl ValueString { pub fn to_bigint(&self) -> util::BigInt { - util::BigInt::new_from_str(&self.utf8_contents) + let bytes: Vec = match self.encoding + { + StringEncoding::Utf8 => self.utf8_contents.bytes().collect(), + StringEncoding::Utf16BE => self.utf8_contents.encode_utf16().flat_map(|v| v.to_be_bytes()).collect(), + StringEncoding::Utf16LE => self.utf8_contents.encode_utf16().flat_map(|v| v.to_le_bytes()).collect(), + StringEncoding::UnicodeBE => self.utf8_contents.chars().flat_map(|c| (c as u32).to_be_bytes()).collect(), + StringEncoding::UnicodeLE => self.utf8_contents.chars().flat_map(|c| (c as u32).to_le_bytes()).collect(), + StringEncoding::Ascii => self.utf8_contents.chars().map(|c| (c as u32) as u8).collect(), // can potentially contain invalid chars + }; + util::BigInt::from_bytes_be(&bytes) } } \ No newline at end of file diff --git a/src/expr/mod.rs b/src/expr/mod.rs index 290ed263..5a8265b6 100644 --- a/src/expr/mod.rs +++ b/src/expr/mod.rs @@ -6,6 +6,7 @@ mod eval; pub use self::expression::Expr; pub use self::expression::Value; +pub use self::expression::StringEncoding; pub use self::expression::ValueString; pub use self::expression::UnaryOp; pub use self::expression::BinaryOp; diff --git a/src/expr/parser.rs b/src/expr/parser.rs index 470e11c7..f2b851da 100644 --- a/src/expr/parser.rs +++ b/src/expr/parser.rs @@ -378,8 +378,8 @@ impl<'a, 'parser> ExpressionParser<'a, 'parser> else if self.parser.next_is(0, syntax::TokenKind::Number) { self.parse_number() } - else if self.parser.next_is(0, syntax::TokenKind::String) - { self.parse_string() } + else if let Some(encoding) = self.parser.next_is_string(0) + { self.parse_string(encoding) } else if self.parser.next_is(0, syntax::TokenKind::KeywordAsm) { self.parse_asm() } @@ -497,9 +497,9 @@ impl<'a, 'parser> ExpressionParser<'a, 'parser> } - fn parse_string(&mut self) -> Result + fn parse_string(&mut self, encoding: expr::StringEncoding) -> Result { - let tk_str = self.parser.expect(syntax::TokenKind::String)?; + let tk_str = self.parser.expect(syntax::TokenKind::String(encoding))?; let string = syntax::excerpt_as_string_contents( self.parser.report.clone().unwrap_or(diagn::RcReport::new()), @@ -511,7 +511,7 @@ impl<'a, 'parser> ExpressionParser<'a, 'parser> expr::Value::String(expr::ValueString { utf8_contents: string, - encoding: "utf8".to_string(), + encoding, })); Ok(expr) diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index 860cdfc7..d9af4aa5 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -449,6 +449,27 @@ impl<'a> Parser<'a> self.tokens[index].kind == kind } + + + pub fn next_is_string(&self, mut nth: usize) -> Option + { + let mut index = self.index; + + while nth > 0 && index < self.tokens.len() + { + nth -= 1; + index += 1; + while index < self.tokens.len() && self.tokens[index].kind.ignorable() + { index += 1; } + } + + if index >= self.tokens.len() + { + return None; + } + + self.tokens[index].kind.is_string() + } pub fn maybe_expect(&mut self, kind: TokenKind) -> Option diff --git a/src/syntax/token.rs b/src/syntax/token.rs index 6ed608a5..8cdedc14 100644 --- a/src/syntax/token.rs +++ b/src/syntax/token.rs @@ -1,4 +1,5 @@ use crate::diagn::{Span, RcReport}; +use crate::expr::StringEncoding; use std::rc::Rc; @@ -20,7 +21,7 @@ pub enum TokenKind LineBreak, Identifier, Number, - String, + String(StringEncoding), KeywordAsm, ParenOpen, ParenClose, @@ -66,11 +67,19 @@ pub enum TokenKind impl TokenKind { + pub fn is_string(self) -> Option { + if let TokenKind::String(encoding) = self { + Some(encoding) + } else { + None + } + } + fn needs_excerpt(self) -> bool { self == TokenKind::Identifier || self == TokenKind::Number || - self == TokenKind::String + self.is_string().is_some() } @@ -130,7 +139,7 @@ impl TokenKind TokenKind::LineBreak => "line break", TokenKind::Identifier => "identifier", TokenKind::Number => "number", - TokenKind::String => "string", + TokenKind::String(_) => "string", TokenKind::KeywordAsm => "`asm` keyword", TokenKind::ParenOpen => "`(`", TokenKind::ParenClose => "`)`", @@ -257,12 +266,22 @@ where S: Into check_for_string (&src[index..]).unwrap_or_else(|| (TokenKind::Error, 1))))))); - let span = Span::new(filename.clone(), index, index + length); + let length_offset = if let Some(encoding) = kind.is_string() { + if encoding != StringEncoding::Utf8 { + 1 + } else { + 0 + } + } else { + 0 + }; + + let span = Span::new(filename.clone(), index, index + length - length_offset); // Get the source excerpt for variable tokens (e.g. identifiers). let excerpt = match kind.needs_excerpt() { - true => Some(src[index..].iter().cloned().take(length).collect()), + true => Some(src[index..].iter().cloned().take(length - length_offset).collect()), false => None }; @@ -401,10 +420,33 @@ fn check_for_string(src: &[char]) -> Option<(TokenKind, usize)> if src[length] != '\"' { return None; } - + length += 1; + + let encoding = if length >= src.len() { + StringEncoding::Utf8 + } else if src[length] == 'W' { + length += 1; + StringEncoding::Utf16BE + } else if src[length] == 'U' { + length += 1; + StringEncoding::UnicodeBE + } else if src[length] == 'w' { + length += 1; + StringEncoding::Utf16LE + } else if src[length] == 'u' { + length += 1; + StringEncoding::UnicodeLE + } else if src[length] == 'a' { + length += 1; + StringEncoding::Ascii + } else if src[length].is_alphanumeric() { + return None + } else { + StringEncoding::Utf8 + }; - Some((TokenKind::String, length)) + Some((TokenKind::String(encoding), length)) } diff --git a/src/test/expr.rs b/src/test/expr.rs index 9237fa07..3fdb641d 100644 --- a/src/test/expr.rs +++ b/src/test/expr.rs @@ -63,6 +63,27 @@ fn test_literals() } +#[test] +fn test_string_literals() +{ + test("\"\"", Pass(expr::Value::make_string("", expr::StringEncoding::Utf8))); + test("\"\"W", Pass(expr::Value::make_string("", expr::StringEncoding::Utf16BE))); + test("\"\"w", Pass(expr::Value::make_string("", expr::StringEncoding::Utf16LE))); + test("\"\"U", Pass(expr::Value::make_string("", expr::StringEncoding::UnicodeBE))); + test("\"\"u", Pass(expr::Value::make_string("", expr::StringEncoding::UnicodeLE))); + test("\"\"a", Pass(expr::Value::make_string("", expr::StringEncoding::Ascii))); + test("\"\"x", Fail(("test", 1, "unexpected character"))); + + test("\"abc\"", Pass(expr::Value::make_string("abc", expr::StringEncoding::Utf8))); + test("\"abc\"W", Pass(expr::Value::make_string("abc", expr::StringEncoding::Utf16BE))); + test("\"abc\"w", Pass(expr::Value::make_string("abc", expr::StringEncoding::Utf16LE))); + test("\"abc\"U", Pass(expr::Value::make_string("abc", expr::StringEncoding::UnicodeBE))); + test("\"abc\"u", Pass(expr::Value::make_string("abc", expr::StringEncoding::UnicodeLE))); + test("\"abc\"a", Pass(expr::Value::make_string("abc", expr::StringEncoding::Ascii))); + test("\"abc\"x", Fail(("test", 1, "unexpected character"))); +} + + #[test] fn test_variables() { diff --git a/src/util/bigint.rs b/src/util/bigint.rs index eed07022..a851e241 100644 --- a/src/util/bigint.rs +++ b/src/util/bigint.rs @@ -22,18 +22,6 @@ impl BigInt } - pub fn new_from_str(s: &str) -> BigInt - { - let bytes = s.bytes().collect::>(); - let bigint = num_bigint::BigInt::from_signed_bytes_be(&bytes); - BigInt - { - bigint, - size: Some(bytes.len() * 8), - } - } - - pub fn as_string(&self) -> String { String::from_utf8_lossy(&self.bigint.to_signed_bytes_be()).to_string() From c9ce7c6e14386721df30f74fd74c42edde64a841 Mon Sep 17 00:00:00 2001 From: Mathis Rech Date: Tue, 26 Oct 2021 18:39:13 +0200 Subject: [PATCH 4/4] Allow strings in integer expressions --- src/asm/state.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/asm/state.rs b/src/asm/state.rs index 5cb2b02e..8d1b40d2 100644 --- a/src/asm/state.rs +++ b/src/asm/state.rs @@ -916,6 +916,23 @@ impl State Ok(()) } } + else if let expr::Value::String(value_s) = value + { + let mut value_int = value_s.to_bigint(); + + if value_int.min_size() > size + { + report.error_span( + &format!("argument out of range for type `u{}`", size), + &span); + Err(()) + } + else + { + value_int.size = Some(size); + Ok(()) + } + } else { report.error_span( @@ -944,6 +961,24 @@ impl State Ok(()) } } + else if let expr::Value::String(value_s) = value + { + let mut value_int = value_s.to_bigint(); + + if (value_int.sign() == 0 && size == 0) || + (value_int.min_size() >= size) + { + report.error_span( + &format!("argument out of range for type `s{}`", size), + &span); + Err(()) + } + else + { + value_int.size = Some(size); + Ok(()) + } + } else { report.error_span( @@ -970,6 +1005,23 @@ impl State Ok(()) } } + else if let expr::Value::String(value_s) = value + { + let mut value_int = value_s.to_bigint(); + + if value_int.min_size() > size + { + report.error_span( + &format!("argument out of range for type `i{}`", size), + &span); + Err(()) + } + else + { + value_int.size = Some(size); + Ok(()) + } + } else { report.error_span( @@ -1232,7 +1284,7 @@ impl State State::eval_fn_check_arg_number(info, 1)?; if State::eval_fn_check_unknown_arg(info, 0, self.is_first_pass) { - return Ok(expr::Value::make_integer(util::BigInt::new_from_str(""))); + return Ok(expr::Value::make_integer(util::BigInt::from_bytes_be(&"".bytes().collect::>()))); } let value_string = State::eval_fn_get_string_arg(info, 0)?;