mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
zkas: Unify error functions into an error emitter.
This commit is contained in:
@@ -1,27 +1,23 @@
|
||||
use std::{
|
||||
io,
|
||||
io::{stdin, stdout, Read, Write},
|
||||
process,
|
||||
str::Chars,
|
||||
};
|
||||
|
||||
use termion::{color, style};
|
||||
|
||||
use super::{
|
||||
ast::{
|
||||
Constant, Constants, StatementType, Statements, Var, Variable, Variables, Witness,
|
||||
Witnesses,
|
||||
},
|
||||
error::ErrorEmitter,
|
||||
types::Type,
|
||||
};
|
||||
|
||||
pub struct Analyzer {
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
pub constants: Constants,
|
||||
pub witnesses: Witnesses,
|
||||
pub statements: Statements,
|
||||
pub stack: Variables,
|
||||
error: ErrorEmitter,
|
||||
}
|
||||
|
||||
impl Analyzer {
|
||||
@@ -34,15 +30,10 @@ impl Analyzer {
|
||||
) -> Self {
|
||||
// For nice error reporting, we'll load everything into a string
|
||||
// vector so we have references to lines.
|
||||
let lines = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
Analyzer {
|
||||
file: filename.to_string(),
|
||||
lines,
|
||||
constants,
|
||||
witnesses,
|
||||
statements,
|
||||
stack: vec![],
|
||||
}
|
||||
let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
let error = ErrorEmitter::new("Semantic", filename, lines.clone());
|
||||
|
||||
Analyzer { constants, witnesses, statements, stack: vec![], error }
|
||||
}
|
||||
|
||||
pub fn analyze_types(&mut self) {
|
||||
@@ -62,7 +53,7 @@ impl Analyzer {
|
||||
// It's kinda ugly.
|
||||
if arg_types[0] == Type::BaseArray || arg_types[0] == Type::ScalarArray {
|
||||
if statement.args.is_empty() {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Passed no arguments to `{:?}` call. Expected at least 1.",
|
||||
statement.opcode
|
||||
@@ -81,7 +72,7 @@ impl Analyzer {
|
||||
};
|
||||
|
||||
if arg_types[0] == Type::BaseArray && var_type != Type::Base {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Incorrect argument type. Expected `{:?}`, got `{:?}`",
|
||||
arg_types[0],
|
||||
@@ -93,7 +84,7 @@ impl Analyzer {
|
||||
}
|
||||
|
||||
if arg_types[0] == Type::ScalarArray && var_type != Type::Scalar {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Incorrect argument type. Expected `{:?}`, got `{:?}`",
|
||||
arg_types[0],
|
||||
@@ -108,7 +99,7 @@ impl Analyzer {
|
||||
arg.typ = var_type;
|
||||
args.push(arg);
|
||||
} else {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Unknown argument reference `{}`.", i.name),
|
||||
i.line,
|
||||
i.column,
|
||||
@@ -117,7 +108,7 @@ impl Analyzer {
|
||||
}
|
||||
} else {
|
||||
if statement.args.len() != arg_types.len() {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Incorrent number of args to `{:?}` call. Expected {}, got {}",
|
||||
statement.opcode,
|
||||
@@ -138,7 +129,7 @@ impl Analyzer {
|
||||
};
|
||||
|
||||
if var_type != arg_types[idx] {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Incorrect argument type. Expected `{:?}`, got `{:?}`",
|
||||
arg_types[idx], var_type,
|
||||
@@ -152,7 +143,7 @@ impl Analyzer {
|
||||
arg.typ = var_type;
|
||||
args.push(arg);
|
||||
} else {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Unknown argument reference `{}`.", i.name),
|
||||
i.line,
|
||||
i.column,
|
||||
@@ -213,7 +204,7 @@ impl Analyzer {
|
||||
if let Some(index) = stack.iter().position(|&r| r == &arg.name) {
|
||||
println!("Found at stack index {}", index);
|
||||
} else {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Could not find `{}` on the stack", arg.name),
|
||||
arg.line,
|
||||
arg.column,
|
||||
@@ -283,31 +274,6 @@ impl Analyzer {
|
||||
None
|
||||
}
|
||||
|
||||
fn error(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line {}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
Analyzer::abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}Semantic error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
fn pause() {
|
||||
let msg = b"[Press Enter to continue]\r";
|
||||
let mut stdout = stdout();
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::{io, io::Write, process, str::Chars};
|
||||
use std::str::Chars;
|
||||
|
||||
use termion::{color, style};
|
||||
|
||||
use super::ast::{Constants, StatementType, Statements, Witnesses};
|
||||
use super::{
|
||||
ast::{Constants, StatementType, Statements, Witnesses},
|
||||
error::ErrorEmitter,
|
||||
};
|
||||
use crate::util::serial::{serialize, VarInt};
|
||||
|
||||
/// Version of the binary
|
||||
@@ -11,12 +12,11 @@ pub const BINARY_VERSION: u8 = 1;
|
||||
pub const MAGIC_BYTES: [u8; 4] = [0x0b, 0x00, 0xb1, 0x35];
|
||||
|
||||
pub struct Compiler {
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
constants: Constants,
|
||||
witnesses: Witnesses,
|
||||
statements: Statements,
|
||||
debug_info: bool,
|
||||
error: ErrorEmitter,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
@@ -30,8 +30,10 @@ impl Compiler {
|
||||
) -> Self {
|
||||
// For nice error reporting, we'll load everything into a string
|
||||
// vector so we have references to lines.
|
||||
let lines = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
Compiler { file: filename.to_string(), lines, constants, witnesses, statements, debug_info }
|
||||
let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
let error = ErrorEmitter::new("Compiler", filename, lines.clone());
|
||||
|
||||
Compiler { constants, witnesses, statements, debug_info, error }
|
||||
}
|
||||
|
||||
pub fn compile(&self) -> Vec<u8> {
|
||||
@@ -77,7 +79,7 @@ impl Compiler {
|
||||
continue
|
||||
}
|
||||
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Failed finding a stack reference for `{}`", arg.name),
|
||||
arg.line,
|
||||
arg.column,
|
||||
@@ -104,29 +106,4 @@ impl Compiler {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn error(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line {}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
Compiler::abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}Compiler error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
41
src/zkas/error.rs
Normal file
41
src/zkas/error.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use std::{io, io::Write, process};
|
||||
|
||||
use termion::{color, style};
|
||||
|
||||
pub(super) struct ErrorEmitter {
|
||||
namespace: String,
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
}
|
||||
|
||||
impl ErrorEmitter {
|
||||
pub fn new(namespace: &str, file: &str, lines: Vec<String>) -> Self {
|
||||
Self { namespace: namespace.to_string(), file: file.to_string(), lines }
|
||||
}
|
||||
|
||||
pub fn emit(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line{}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
self.abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(&self, msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}{} error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
self.namespace,
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{io, io::Write, process, str::Chars};
|
||||
use std::str::Chars;
|
||||
|
||||
use termion::{color, style};
|
||||
use super::error::ErrorEmitter;
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
|
||||
pub enum TokenType {
|
||||
@@ -33,9 +33,8 @@ impl Token {
|
||||
}
|
||||
|
||||
pub struct Lexer<'a> {
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
source: Chars<'a>,
|
||||
error: ErrorEmitter,
|
||||
}
|
||||
|
||||
impl<'a> Lexer<'a> {
|
||||
@@ -43,7 +42,9 @@ impl<'a> Lexer<'a> {
|
||||
// For nice error reporting, we'll load everything into a string
|
||||
// vector so we have references to lines.
|
||||
let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
Lexer { file: filename.to_string(), lines, source }
|
||||
let error = ErrorEmitter::new("Lexer", filename, lines.clone());
|
||||
|
||||
Self { source, error }
|
||||
}
|
||||
|
||||
pub fn lex(self) -> Vec<Token> {
|
||||
@@ -78,7 +79,11 @@ impl<'a> Lexer<'a> {
|
||||
|
||||
if in_string {
|
||||
// TODO: Allow newlines in strings?
|
||||
self.error(format!("Invalid ending in string `{}`", &strbuf), lineno, column);
|
||||
self.error.emit(
|
||||
format!("Invalid ending in string `{}`", &strbuf),
|
||||
lineno,
|
||||
column,
|
||||
);
|
||||
}
|
||||
|
||||
in_comment = false;
|
||||
@@ -141,7 +146,7 @@ impl<'a> Lexer<'a> {
|
||||
|
||||
if c == '"' && !in_string {
|
||||
if in_symbol {
|
||||
self.error(format!("Illegal char `{}` for symbol", c), lineno, column);
|
||||
self.error.emit(format!("Illegal char `{}` for symbol", c), lineno, column);
|
||||
}
|
||||
in_string = true;
|
||||
continue
|
||||
@@ -149,7 +154,11 @@ impl<'a> Lexer<'a> {
|
||||
|
||||
if c == '"' && in_string {
|
||||
if strbuf.is_empty() {
|
||||
self.error(format!("Invalid ending in string `{}`", &strbuf), lineno, column);
|
||||
self.error.emit(
|
||||
format!("Invalid ending in string `{}`", &strbuf),
|
||||
lineno,
|
||||
column,
|
||||
);
|
||||
}
|
||||
|
||||
in_string = false;
|
||||
@@ -229,41 +238,16 @@ impl<'a> Lexer<'a> {
|
||||
tokens.push(Token::new("=".to_string(), TokenType::Assign, lineno, column));
|
||||
continue
|
||||
}
|
||||
_ => self.error(format!("Invalid token `{}`", c), lineno, column - 1),
|
||||
_ => self.error.emit(format!("Invalid token `{}`", c), lineno, column - 1),
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
self.error(format!("Invalid token `{}`", c), lineno, column - 1);
|
||||
self.error.emit(format!("Invalid token `{}`", c), lineno, column - 1);
|
||||
}
|
||||
|
||||
tokens
|
||||
}
|
||||
|
||||
fn error(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line {}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
Lexer::abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}Lexer error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_letter(ch: char) -> bool {
|
||||
|
||||
@@ -6,6 +6,8 @@ pub mod ast;
|
||||
pub mod compiler;
|
||||
/// Binary decoder
|
||||
pub mod decoder;
|
||||
/// Error emitter
|
||||
mod error;
|
||||
/// Lexer module
|
||||
pub mod lexer;
|
||||
/// Language opcodes
|
||||
|
||||
@@ -1,31 +1,32 @@
|
||||
use std::{io, io::Write, iter::Peekable, process, str::Chars};
|
||||
use std::{iter::Peekable, str::Chars};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
use termion::{color, style};
|
||||
|
||||
use super::{
|
||||
ast::{
|
||||
Constant, Constants, Statement, StatementType, Statements, UnparsedConstants,
|
||||
UnparsedWitnesses, Variable, Witness, Witnesses,
|
||||
},
|
||||
error::ErrorEmitter,
|
||||
lexer::{Token, TokenType},
|
||||
opcode::Opcode,
|
||||
types::Type,
|
||||
};
|
||||
|
||||
pub struct Parser {
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
tokens: Vec<Token>,
|
||||
error: ErrorEmitter,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new(filename: &str, source: Chars, tokens: Vec<Token>) -> Self {
|
||||
// For nice error reporting, we'll load everything into a string
|
||||
// vector so we have references to lines.
|
||||
let lines = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
Parser { file: filename.to_string(), lines, tokens }
|
||||
let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
let error = ErrorEmitter::new("Parser", filename, lines.clone());
|
||||
|
||||
Parser { tokens, error }
|
||||
}
|
||||
|
||||
pub fn parse(self) -> (Constants, Witnesses, Statements) {
|
||||
@@ -93,7 +94,9 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
x => self.error(format!("Unknown `{}` proof section", x), t.line, t.column),
|
||||
x => {
|
||||
self.error.emit(format!("Unknown `{}` proof section", x), t.line, t.column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +117,7 @@ impl Parser {
|
||||
|
||||
// TODO: Do we need this?
|
||||
if namespace_found && namespace != constant_tokens[0].token {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Found `{}` namespace. Expected `{}`.",
|
||||
constant_tokens[0].token, namespace
|
||||
@@ -134,7 +137,7 @@ impl Parser {
|
||||
|
||||
while let Some((typ, name, comma)) = constants_inner.next_tuple() {
|
||||
if comma.token_type != TokenType::Comma {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Separator is not a comma".to_string(),
|
||||
comma.line,
|
||||
comma.column,
|
||||
@@ -142,7 +145,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if constants_map.contains_key(name.token.as_str()) {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Section `constant` already contains the token `{}`.",
|
||||
&name.token
|
||||
@@ -164,7 +167,7 @@ impl Parser {
|
||||
|
||||
// TODO: Do we need this?
|
||||
if namespace_found && namespace != contract_tokens[0].token {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Found `{}` namespace. Expected `{}`.",
|
||||
contract_tokens[0].token, namespace
|
||||
@@ -184,7 +187,7 @@ impl Parser {
|
||||
|
||||
while let Some((typ, name, comma)) = contract_inner.next_tuple() {
|
||||
if comma.token_type != TokenType::Comma {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Separator is not a comma".to_string(),
|
||||
comma.line,
|
||||
comma.column,
|
||||
@@ -192,7 +195,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if contract_map.contains_key(name.token.as_str()) {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Section `contract` already contains the token `{}`.",
|
||||
&name.token
|
||||
@@ -213,7 +216,7 @@ impl Parser {
|
||||
self.check_section_structure("circuit", contract_tokens.clone());
|
||||
|
||||
if circuit_tokens[circuit_tokens.len() - 2].token_type != TokenType::Semicolon {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Circuit section does not end with a semicolon. Would never finish parsing.".to_string(),
|
||||
circuit_tokens[circuit_tokens.len()-2].line,
|
||||
circuit_tokens[circuit_tokens.len()-2].column
|
||||
@@ -222,7 +225,7 @@ impl Parser {
|
||||
|
||||
// TODO: Do we need this?
|
||||
if namespace_found && namespace != circuit_tokens[0].token {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Found `{}` namespace. Expected `{}`.",
|
||||
circuit_tokens[0].token, namespace
|
||||
@@ -271,7 +274,7 @@ impl Parser {
|
||||
|
||||
fn check_section_structure(&self, section: &str, tokens: Vec<Token>) {
|
||||
if tokens[0].token_type != TokenType::String {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("{} section declaration must start with a naming string.", section),
|
||||
tokens[0].line,
|
||||
tokens[0].column,
|
||||
@@ -279,7 +282,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if tokens[1].token_type != TokenType::LeftBrace {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"{} section opening is not correct. Must be opened with a left brace `{{`",
|
||||
section
|
||||
@@ -290,7 +293,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if tokens[tokens.len() - 1].token_type != TokenType::RightBrace {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"{} section closing is not correct. Must be closed with a right brace `}}`",
|
||||
section
|
||||
@@ -303,7 +306,7 @@ impl Parser {
|
||||
if (section == "constant" || section == "contract") &&
|
||||
tokens[2..tokens.len() - 1].len() % 3 != 0
|
||||
{
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Invalid number of elements in `{}` section. Must be pairs of `type:name` separated with a comma `,`",
|
||||
section
|
||||
@@ -319,7 +322,7 @@ impl Parser {
|
||||
|
||||
for (k, v) in ast {
|
||||
if &v.0.token != k {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Constant name `{}` doesn't match token `{}`.", v.0.token, k),
|
||||
v.0.line,
|
||||
v.0.column,
|
||||
@@ -327,7 +330,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if v.0.token_type != TokenType::Symbol {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Constant name `{}` is not a symbol.", v.0.token),
|
||||
v.0.line,
|
||||
v.0.column,
|
||||
@@ -335,7 +338,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if v.1.token_type != TokenType::Symbol {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Constant type `{}` is not a symbol.", v.1.token),
|
||||
v.1.line,
|
||||
v.1.column,
|
||||
@@ -353,7 +356,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
x => {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("`{}` is an illegal constant type", x),
|
||||
v.1.line,
|
||||
v.1.column,
|
||||
@@ -370,7 +373,7 @@ impl Parser {
|
||||
|
||||
for (k, v) in ast {
|
||||
if &v.0.token != k {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Witness name `{}` doesn't match token `{}`.", v.0.token, k),
|
||||
v.0.line,
|
||||
v.0.column,
|
||||
@@ -378,7 +381,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if v.0.token_type != TokenType::Symbol {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Witness name `{}` is not a symbol.", v.0.token),
|
||||
v.0.line,
|
||||
v.0.column,
|
||||
@@ -386,7 +389,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if v.1.token_type != TokenType::Symbol {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Witness type `{}` is not a symbol.", v.1.token),
|
||||
v.1.line,
|
||||
v.1.column,
|
||||
@@ -440,7 +443,11 @@ impl Parser {
|
||||
}
|
||||
|
||||
x => {
|
||||
self.error(format!("`{}` is an illegal witness type", x), v.1.line, v.1.column);
|
||||
self.error.emit(
|
||||
format!("`{}` is an illegal witness type", x),
|
||||
v.1.line,
|
||||
v.1.column,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -461,7 +468,7 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
if left_paren != right_paren {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Incorrect number of left and right parenthesis for statement.".to_string(),
|
||||
statement[0].line,
|
||||
statement[0].column,
|
||||
@@ -508,7 +515,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if !parsing {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Illegal token `{}`", next_token.token),
|
||||
next_token.line,
|
||||
next_token.column,
|
||||
@@ -614,7 +621,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
x => {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Unimplemented function call `{}`", x),
|
||||
token.line,
|
||||
token.column,
|
||||
@@ -635,7 +642,7 @@ impl Parser {
|
||||
) -> Vec<Variable> {
|
||||
if let Some(next_token) = iter.peek() {
|
||||
if next_token.token_type != TokenType::LeftParen {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Invalid function call opening. Must start with a `(`".to_string(),
|
||||
next_token.line,
|
||||
next_token.column,
|
||||
@@ -644,7 +651,7 @@ impl Parser {
|
||||
// Skip the opening parenthesis
|
||||
iter.next();
|
||||
} else {
|
||||
self.error("Premature ending of statement".to_string(), token.line, token.column);
|
||||
self.error.emit("Premature ending of statement".to_string(), token.line, token.column);
|
||||
}
|
||||
|
||||
// Eat up function arguments
|
||||
@@ -663,7 +670,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if sep.token_type != TokenType::Comma {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Argument separator is not a comma (`,`)".to_string(),
|
||||
sep.line,
|
||||
sep.column,
|
||||
@@ -673,29 +680,4 @@ impl Parser {
|
||||
|
||||
args
|
||||
}
|
||||
|
||||
fn error(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line {}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
Parser::abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}Parser error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user