diff --git a/README.md b/README.md index 0b9470db..2c4fc5c3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Trc is a stack-based programming language -Trc's syntax is easy,and have full toolchain.It is easy to learn modern c++ and compiler,too. +Trc's syntax is easy,and have full toolchain. It is easy to learn modern c++ and compiler,too. ## language @@ -81,6 +81,8 @@ Wechat:angelgel2020 QQ:3570249647 +email: ```limuyang202011@163.com``` + ## Referenced Open-source software | Library |Usage | diff --git a/rust/Cargo.lock b/rust/Cargo.lock index fa287836..53c16b03 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -136,6 +136,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + [[package]] name = "getrandom" version = "0.2.11" @@ -354,6 +360,7 @@ version = "0.1.0" dependencies = [ "clap", "colored", + "downcast-rs", "gettext-rs", "rand", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index eeed9e23..ba9a3781 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -15,3 +15,4 @@ rand = "0.8.5" clap = { version = "4.4.18", features = ["derive"] } gettext-rs = "0.7.0" colored = "2.1.0" +downcast-rs = "1.2.0" diff --git a/rust/locales/zh_CN/LC_MESSAGES/trans.po b/rust/locales/zh_CN/LC_MESSAGES/trans.po index c761e241..0cf3d469 100644 --- a/rust/locales/zh_CN/LC_MESSAGES/trans.po +++ b/rust/locales/zh_CN/LC_MESSAGES/trans.po @@ -11,8 +11,14 @@ msgstr "语法错误" msgid "OperatorError" msgstr "操作符错误" +msgid "VmError" +msgstr "虚拟机错误" + msgid "this string should be ended with {}" msgstr "这个字符串应当以{}结束" msgid "operator {} is not supported for type {}" msgstr "操作符{}不支持类型{}" + +msgid "The number of data of vm stack is not correct, should have {} data" +msgstr "虚拟机栈中数据数量不正确,期望有{}个数据" diff --git a/rust/src/base/error.rs b/rust/src/base/error.rs index b14f7765..913305af 100644 --- a/rust/src/base/error.rs +++ b/rust/src/base/error.rs @@ -5,8 +5,11 @@ const EXIT_FAILURE: i32 = 1; pub const SYNTAX_ERROR: &str = "SyntaxError"; pub const OPERATOR_ERROR: &str = "OperatorError"; +pub const VM_ERROR:&str = "VmError"; + pub const STRING_WITHOUT_END: &str = "this string should be ended with {}"; pub const OPERATOR_IS_NOT_SUPPORT: &str = "operator {} is not supported for type {}"; +pub const VM_DATA_NUMBER:&str = "The number of data of vm stack is not correct, should have {} data"; pub struct ErrorInfo { pub message: String, @@ -28,6 +31,9 @@ pub trait ErrorContent { fn get_line(&self) -> usize; } +/// report error in vm or compiler +/// we will translate the error type to gettextrs +/// but you should translate the error messgae by caller pub fn report_error(content: &impl ErrorContent, info: ErrorInfo) { eprintln!("Error in line {}", content.get_line()); eprintln!("In module {}", content.get_module_name()); diff --git a/rust/src/compiler.rs b/rust/src/compiler.rs index 0274f029..ba288750 100644 --- a/rust/src/compiler.rs +++ b/rust/src/compiler.rs @@ -216,7 +216,6 @@ impl TokenIo for FileSource { pub struct Compiler { // to support read from stdin and file input: Box, - line: usize, const_pool: ValuePool, option: Option, content: Content, @@ -229,7 +228,6 @@ impl Compiler { let f = std::fs::File::open(filename); Compiler { input: Box::new(FileSource::new(f.unwrap())), - line: 1, const_pool: ValuePool::new(), option, content: Content::new(cfg::MAIN_MODULE_NAME), @@ -244,7 +242,6 @@ impl Compiler { fn new_string_compiler(option: Option, source: &str) -> Self { Compiler { input: Box::new(StringSource::new(String::from(source))), - line: 1, const_pool: ValuePool::new(), option, content: Content::new(cfg::MAIN_MODULE_NAME), diff --git a/rust/src/compiler/token.rs b/rust/src/compiler/token.rs index 833ce350..32c9a777 100644 --- a/rust/src/compiler/token.rs +++ b/rust/src/compiler/token.rs @@ -33,11 +33,45 @@ enum TokenType { MOD, // // EXACT_DIVISION, + // += + SELF_ADD, + // -= + SELF_SUB, + // *= + SELF_MUL, + // /= + SELF_DIV, + // //= + SELF_EXTRA_DIV, + // %= + SELF_MOD, + // ** + POWER, + // **= + SELF_POWER, INT_VALUE, STRING_VALUE, FLOAT_VALUE, LONG_INT_VALUE, LONG_FLOAT_VALUE, + // = + ASSIGN, + // := + STORE, + // == + EQUAL, + // != + UNEQUAL, + // > + GREATER, + // < + LESS, + // <= + LESS_EQUAL, + // >= + GREATER_EQUAL, + // ! + NOT, } #[derive(PartialEq, Debug)] @@ -75,6 +109,37 @@ impl Iterator for TokenLex<'_> { } } +macro_rules! binary_symbol { + ($a:expr, $b:expr, $binary_sym:expr, $sself:expr) => {{ + let c = $sself.compiler_data.input.read(); + if c == $binary_sym { + return Token::new($b, None) + } + $sself.compiler_data.input.unread(c); + Token::new($a, None) + }} +} + +macro_rules! self_symbol { +($sym:expr, $self_sym:expr, $sself:expr) => + {{ + binary_symbol!($sym, $self_sym, '=', $sself) + }} +} + +macro_rules! double_symbol { + ($before_sym:expr, $before_self_sym:expr, $matched_sym:expr, $matched_self_sym:expr, matched_char:expr, $sself:expr) => { + { + let c = $sself.compiler_data.input.read(); + if c == $matched_char { + return self_symbol!($matched_sym, $matched_self_sym, self) + } + self.compiler_data.input.unread(c); + return self_symbol!($before_sym, $before_self_sym, self); + } + }; +} + impl TokenLex<'_> { pub fn new<'a>(compiler_data: &'a mut Compiler) -> TokenLex<'a> { TokenLex { compiler_data } @@ -90,6 +155,29 @@ impl TokenLex<'_> { ']' => Token::new(TokenType::RIGHT_MIDDLE_BRACE, None), '(' => Token::new(TokenType::LEFT_SMALL_BRACE, None), ')' => Token::new(TokenType::RIGHT_SMALL_BRACE, None), + '+' => self_symbol!(TokenType::ADD, TokenType::SELF_ADD, self), + '-' => self_symbol!(TokenType::SUB, TokenType::SELF_SUB, self), + '*' => { + let c = self.compiler_data.input.read(); + if c == '*' { + return self_symbol!(TokenType::POWER, TokenType::SELF_POWER, self) + } + self.compiler_data.input.unread(c); + return self_symbol!(TokenType::MUL, TokenType::SELF_MUL, self); + }, + '%' => self_symbol!(TokenType::MOD, TokenType::SELF_MOD, self), + '/' => { + let c = self.compiler_data.input.read(); + if c == '=' { + return Token::new(TokenType::SELF_DIV, None) + } + self.compiler_data.input.unread(c); + Token::new(TokenType::DIV, None) + }, + '=' => binary_symbol!(TokenType::ASSIGN, TokenType::EQUAL, '=', self), + '!' => binary_symbol!(TokenType::NOT, TokenType::UNEQUAL, '=', self), + '>' => binary_symbol!(TokenType::GREATER, TokenType::GREATER_EQUAL, '=', self), + '<' => binary_symbol!(TokenType::LESS, TokenType::LESS_EQUAL, '=', self), _ => panic!("Not a symbol.Compiler error"), } } @@ -191,7 +279,7 @@ impl TokenLex<'_> { continue; } '\n' => { - self.compiler_data.line += 1; + self.compiler_data.content.add_line(); } _ => break, }, @@ -251,7 +339,17 @@ mod tests { } #[test] - fn test_symbol_lex() {} + fn test_symbol_lex() { + let mut env = Compiler::new_string_compiler( + Option::new(false, InputSource::StringInternal), + r#":{}[]()+=%=//= // /=** *=*"#, + ); + let mut t = TokenLex::new(&mut env); + let res = vec![ + Token::new(TokenType::STRING_VALUE, Some(Data::Ind(0))) + ]; + check(&mut t, res); + } #[test] fn test_string_lex() { diff --git a/rust/src/tvm.rs b/rust/src/tvm.rs index ac754715..022a058f 100644 --- a/rust/src/tvm.rs +++ b/rust/src/tvm.rs @@ -1,9 +1,13 @@ mod algo; mod function; mod types; +mod def; + +use clap::error; +use gettextrs::gettext; use crate::{ - base::error::ErrorContent, + base::error::{ErrorContent, report_error, ErrorInfo, VM_DATA_NUMBER, VM_ERROR}, cfg, }; @@ -88,6 +92,7 @@ enum Opcode { Sub, Mul, Div, + ExtraDiv, Mod, Eq, Ne, @@ -104,6 +109,30 @@ enum Opcode { PopFrame, // create a frame to hold the function NewFrame, + // Load a int from const pool + LoadInt +} + +/// reduce the duplicate code to solve the operator running +macro_rules! OP { + ($trait_used:ident, $sself:expr) => {{ + let t1 = $sself.dynadata.obj_stack.pop(); + let t2 = $sself.dynadata.obj_stack.pop(); + if t1.is_none() || t2.is_none() { + report_error(&$sself.run_contnet, ErrorInfo::new(gettext!(VM_DATA_NUMBER, 2), VM_ERROR)); + } + let t1 = t1.unwrap(); + let t2 = t2.unwrap(); + let ret = t1.$trait_used(t2); + match ret { + Err(e) => { + report_error(&$sself.run_contnet, e); + }, + Ok(t) => { + $sself.dynadata.obj_stack.push(t); + } + } + }}; } impl<'a> Vm<'a> { @@ -121,13 +150,20 @@ impl<'a> Vm<'a> { pub fn run(&mut self) { while self.pc < self.inst.len() { match self.inst[self.pc].opcode { - Opcode::Add => { - let t1 = self.dynadata.obj_stack.pop(); - let t2 = self.dynadata.obj_stack.pop(); - if t1.is_none() || t2.is_none() {} - } - Opcode::Div => {} - Opcode::Gt => {} + Opcode::Add => OP!(add, self), + Opcode::Sub => OP!(sub, self), + Opcode::Mul => OP!(mul, self), + Opcode::Div => OP!(div, self), + Opcode::ExtraDiv => OP!(extra_div, self), + Opcode::Mod => OP!(modd, self), + Opcode::Gt => OP!(gt, self), + Opcode::Lt => OP!(lt, self), + Opcode::Ge => OP!(ge, self), + Opcode::Le => OP!(le, self), + Opcode::Eq => OP!(eq, self), + Opcode::Ne => OP!(ne, self), + Opcode::And => OP!(and, self), + Opcode::Or => OP!(or, self), Opcode::NewFrame => {} Opcode::PopFrame => { self.dynadata.frames_stack.pop(); diff --git a/rust/src/tvm/def.rs b/rust/src/tvm/def.rs new file mode 100644 index 00000000..e69de29b diff --git a/rust/src/tvm/function.rs b/rust/src/tvm/function.rs index 3301be75..cc5ec25b 100644 --- a/rust/src/tvm/function.rs +++ b/rust/src/tvm/function.rs @@ -1,3 +1,5 @@ +use super::types::TrcObj; + pub struct Func { name: String, } diff --git a/rust/src/tvm/types.rs b/rust/src/tvm/types.rs index e1e0ae62..803e4915 100644 --- a/rust/src/tvm/types.rs +++ b/rust/src/tvm/types.rs @@ -1,20 +1,79 @@ use crate::base::error; +use downcast_rs::{impl_downcast, Downcast}; use gettextrs::gettext; -mod data_structure; -mod trcfloat; -mod trcint; -mod trcstr; +pub mod data_structure; +pub mod trcfloat; +pub mod trcint; +pub mod trcstr; +pub mod trcbool; -pub trait TrcObj { - fn output(&self) {} - - fn add(&self, _: Box) -> Result, error::ErrorInfo> { +macro_rules! unsupported_operator { + ($operator_name:expr, $sself:expr) => { Err(error::ErrorInfo::new( - gettext!(error::OPERATOR_IS_NOT_SUPPORT, "+", self.get_type_name()), + gettext!(error::OPERATOR_IS_NOT_SUPPORT, $operator_name, $sself.get_type_name()), error::SYNTAX_ERROR, )) } +} + +/// help to generate the same error reporter functions +macro_rules! operators { + ($($traie_name:ident => $oper_name:expr),*) => { + $(fn $traie_name(&self, _ :Box) -> TypeError { + unsupported_operator!($oper_name, self) + })* + }; +} + +#[macro_export] +macro_rules! impl_oper { + ($trait_oper_fn_name:ident, $oper:tt, $error_oper_name:expr, $self_type:ident) => { + fn $trait_oper_fn_name(&self, other:Box) -> TypeError { + match other.downcast_ref::<$self_type>() { + Some(v) => { + Ok(Box::new(TrcInt::new(self.value $oper v.value))) + }, + None => { + Err(ErrorInfo::new(gettext!(OPERATOR_IS_NOT_SUPPORT, $error_oper_name, other.get_type_name()), OPERATOR_ERROR)) + } + } + } + }; +} + +#[macro_export] +macro_rules! batch_impl_opers { + ($($trait_oper_fn_name:ident => $oper:tt, $error_oper_name:expr, $self_type:ident),*) => { + $( + impl_oper!($trait_oper_fn_name, $oper, $error_oper_name, $self_type); + )* + }; +} + +type TypeError= Result, error::ErrorInfo>; + +pub trait TrcObj:Downcast { + fn output(&self) {} + + operators!( + sub => "-", + mul => "*", + add => "+", + div => "/", + extra_div => "//", + modd => "%", + gt => ">", + lt => "<", + eq => "==", + ne => "!=", + ge => ">=", + le => "<=", + and => "and", + or => "or" + ); fn get_type_name(&self) -> &str; } + +impl_downcast!(TrcObj); diff --git a/rust/src/tvm/types/trcbool.rs b/rust/src/tvm/types/trcbool.rs new file mode 100644 index 00000000..8d10493b --- /dev/null +++ b/rust/src/tvm/types/trcbool.rs @@ -0,0 +1,10 @@ +use super::TrcObj; +pub struct TrcBool { + +} + +impl TrcObj for TrcBool { + fn get_type_name(&self) -> &str { + "bool" + } +} diff --git a/rust/src/tvm/types/trcfloat.rs b/rust/src/tvm/types/trcfloat.rs index 8b137891..d3f5d719 100644 --- a/rust/src/tvm/types/trcfloat.rs +++ b/rust/src/tvm/types/trcfloat.rs @@ -1 +1,11 @@ +use super::TrcObj; +pub struct TrcFloat { + +} + +impl TrcObj for TrcFloat { + fn get_type_name(&self) -> &str { + "float" + } +} diff --git a/rust/src/tvm/types/trcint.rs b/rust/src/tvm/types/trcint.rs index 4edaa8e6..db4f1620 100644 --- a/rust/src/tvm/types/trcint.rs +++ b/rust/src/tvm/types/trcint.rs @@ -1,4 +1,6 @@ -use super::super::Opcode; +use gettextrs::gettext; +use crate::{base::error::{ErrorInfo, OPERATOR_IS_NOT_SUPPORT, OPERATOR_ERROR}, impl_oper, batch_impl_opers}; +use super::{TrcObj, TypeError}; pub struct TrcInt { pub value: i64, @@ -8,10 +10,16 @@ impl TrcInt { pub fn new(value: i64) -> TrcInt { TrcInt { value } } +} - pub fn check_opcode_support(opcode: Opcode) -> bool { - match opcode { - _ => false, - } +impl TrcObj for TrcInt { + fn get_type_name(&self) -> &str { + "int" } + + // impl_oper!(add, +, "+", TrcInt); + batch_impl_opers!( + add => +, "+", TrcInt, + sub => -, "-", TrcInt + ); } diff --git a/rust/src/tvm/types/trcstr.rs b/rust/src/tvm/types/trcstr.rs index 8b137891..0ad7be3d 100644 --- a/rust/src/tvm/types/trcstr.rs +++ b/rust/src/tvm/types/trcstr.rs @@ -1 +1,11 @@ +use super::TrcObj; +pub struct TrcStr { + +} + +impl TrcObj for TrcStr { + fn get_type_name(&self) -> &str { + "str" + } +}