From 6a5788259b22f70f3bceb13596f6377a721e7801 Mon Sep 17 00:00:00 2001 From: limuy Date: Sun, 24 Mar 2024 10:41:42 +0800 Subject: [PATCH] finish function return --- examples/fast_pow.trc | 13 +++-- examples/func_call.trc | 13 +++++ examples/if.trc | 3 ++ locales/en.toml | 1 + locales/zh-CN.toml | 1 + src/base/error.rs | 1 + src/compiler/ast.rs | 92 +++++++++++++++++++++++++----------- src/compiler/ast/ast_base.rs | 9 ++-- src/tools/dis.rs | 12 ++--- src/tvm.rs | 1 + 10 files changed, 100 insertions(+), 46 deletions(-) diff --git a/examples/fast_pow.trc b/examples/fast_pow.trc index 8f07f9fa..015cadc6 100644 --- a/examples/fast_pow.trc +++ b/examples/fast_pow.trc @@ -3,13 +3,12 @@ func fastpow(a: int, b: int) int { if b == 0 { return 1 } - if b == 1 { - return a - } - tmp := fastpow(a, b / 2); - tmp = tmp * tmp; + tmp := fastpow(a, b // 2) + tmp = tmp * tmp if b % 2 != 0 { - tmp = tmp * a + tmp = tmp * a } - return tmp; + return tmp } + +print("{}", fastpow(2, 3)) diff --git a/examples/func_call.trc b/examples/func_call.trc index cc0e0eae..9d7de3de 100644 --- a/examples/func_call.trc +++ b/examples/func_call.trc @@ -1,6 +1,19 @@ func t1(a: int, b: int, c: int) { println("{}{}{}", a, b, c) } + +func test_complex(a:int) { + if a==89 { + print("i am 89") + } + if a ==90{ + print("i am 90") + } +} + +func oo(p: int) { + oo(p/2) +} t1(90, 89, 77) a:=9 b:=8 diff --git a/examples/if.trc b/examples/if.trc index 19362335..8d25caa3 100644 --- a/examples/if.trc +++ b/examples/if.trc @@ -2,6 +2,9 @@ a:=90 if a==90 { println("i equal to 90") } +if a==89 { + println("i equal to 89") +} if a < 89 { println("i less than 90") } else { diff --git a/locales/en.toml b/locales/en.toml index 1b8dd859..3e47dcea 100644 --- a/locales/en.toml +++ b/locales/en.toml @@ -23,6 +23,7 @@ unexpected_token = "token %{0} is not expected" unclosed_comment = "unclosed comment" char_error = "char should be the format like 'x'." expected_expr = "expected expression" +return_should_in_function = "return should in function" [compiler.symbolerror] not_found_sym = "Symbol %{0} not found" diff --git a/locales/zh-CN.toml b/locales/zh-CN.toml index cb7e86bb..8c370e97 100644 --- a/locales/zh-CN.toml +++ b/locales/zh-CN.toml @@ -23,6 +23,7 @@ unclosed_comment = "未闭合的注释" prefix_float = "前缀%{0}不能对浮点数使用" unexpected_token = "token %{0}不是被期望的" expected_expr = "期望表达式" +return_should_in_function = "return必须在函数内部" [compiler.symbolerror] not_found_sym = "未找到符号%{0}" diff --git a/src/base/error.rs b/src/base/error.rs index 8a31d1b5..38dad691 100644 --- a/src/base/error.rs +++ b/src/base/error.rs @@ -35,6 +35,7 @@ pub const UNCLODED_COMMENT: &str = "compiler.syntaxerror.unclosed_comment"; pub const UNCLOSED_FORMAT: &str = "compiler.formatstringerror.unclosed_format"; pub const ARGUMENT_CANNOT_BE_VOID: &str = "compiler.argumenterror.void_argu"; pub const JUST_ACCEPT_BOOL: &str = "compiler.typerror.if_while_accept_bool"; +pub const RETURN_SHOULD_IN_FUNCTION: &str = "compiler.syntaxerror.return_should_in_function"; #[derive(Debug)] pub struct ErrorInfo { diff --git a/src/compiler/ast.rs b/src/compiler/ast.rs index 279c2739..6a9c3d8d 100644 --- a/src/compiler/ast.rs +++ b/src/compiler/ast.rs @@ -518,7 +518,7 @@ impl<'a> AstBuilder<'a> { let name_id = match self.self_scope.as_ref().borrow_mut().insert_sym(funcname) { Some(v) => v, None => { - return self.report_error(ErrorInfo::new( + return self.gen_error(ErrorInfo::new( t!( SYMBOL_REDEFINED, "0" = self.token_lexer.const_pool.id_name[funcname] @@ -544,22 +544,25 @@ impl<'a> AstBuilder<'a> { self.get_token_checked(TokenType::Colon)?; ty_list.push(self.get_ty(false)?); } - let tmp = self.token_lexer.next_token()?; - let return_ty = match tmp.tp { - TokenType::Arrow => TypeAllowNull::Yes(self.get_ty(false)?), - _ => { - self.token_lexer.next_back(tmp); - TypeAllowNull::No - } + // 返回值解析 + let return_ty = match self.get_ty(true) { + Err(_) => TypeAllowNull::No, + Ok(ty) => TypeAllowNull::Yes(ty), }; let io = IOType::new(ty_list, return_ty, false); self.get_token_checked(TokenType::LeftBigBrace)?; let mut function_body = vec![]; + let mut cnt = 1; loop { let t = self.token_lexer.next_token()?; function_body.push((t.clone(), self.token_lexer.compiler_data.context.get_line())); if t.tp == RightBigBrace { - break; + cnt -= 1; + if cnt == 0 { + break; + } + } else if t.tp == TokenType::LeftBigBrace { + cnt += 1; } } // self.self_scope = tmp.clone(); @@ -637,7 +640,7 @@ impl<'a> AstBuilder<'a> { let sym_idx = match self.self_scope.as_ref().borrow_mut().insert_sym(name) { Some(v) => v, None => { - return self.report_error(ErrorInfo::new( + return self.gen_error(ErrorInfo::new( t!( SYMBOL_REDEFINED, "0" = self.token_lexer.const_pool.id_name[name] @@ -662,7 +665,7 @@ impl<'a> AstBuilder<'a> { let var_type = match self.process_info.get_last_ty() { Some(v) => v, None => { - return self.report_error(ErrorInfo::new(t!(EXPECTED_EXPR), t!(SYNTAX_ERROR))); + return self.gen_error(ErrorInfo::new(t!(EXPECTED_EXPR), t!(SYNTAX_ERROR))); } }; self.new_var(name, var_type)?; @@ -674,13 +677,13 @@ impl<'a> AstBuilder<'a> { let var_type = match self.process_info.get_last_ty() { Some(v) => v, None => { - return self.report_error(ErrorInfo::new(t!(EXPECTED_EXPR), t!(SYNTAX_ERROR))); + return self.gen_error(ErrorInfo::new(t!(EXPECTED_EXPR), t!(SYNTAX_ERROR))); } }; let var = match self.self_scope.as_ref().borrow().get_var(name) { Some(v) => v, None => { - return self.report_error(ErrorInfo::new( + return self.gen_error(ErrorInfo::new( t!( SYMBOL_NOT_FOUND, "0" = self.token_lexer.const_pool.id_name[name] @@ -690,7 +693,7 @@ impl<'a> AstBuilder<'a> { } }; if var.ty != var_type { - return self.report_error(ErrorInfo::new(t!(TYPE_NOT_THE_SAME), t!(TYPE_ERROR))); + return self.gen_error(ErrorInfo::new(t!(TYPE_NOT_THE_SAME), t!(TYPE_ERROR))); } self.modify_var(var.ty, var.addr, self.process_info.is_global); Ok(()) @@ -712,11 +715,11 @@ impl<'a> AstBuilder<'a> { self.expr(false)?; match self.process_info.stack_type.last() { None => { - return self.report_error(ErrorInfo::new(t!(EXPECTED_EXPR), t!(SYNTAX_ERROR))); + return self.gen_error(ErrorInfo::new(t!(EXPECTED_EXPR), t!(SYNTAX_ERROR))); } Some(ty) => { if *ty != self.cache.boolty_id { - return self.report_error(ErrorInfo::new(t!(JUST_ACCEPT_BOOL), t!(TYPE_ERROR))); + return self.gen_error(ErrorInfo::new(t!(JUST_ACCEPT_BOOL), t!(TYPE_ERROR))); } } } @@ -763,6 +766,19 @@ impl<'a> AstBuilder<'a> { fn statement(&mut self) -> RunResult<()> { let t = self.token_lexer.next_token()?; match t.tp { + TokenType::Return => { + if self.process_info.is_global { + return self.gen_error(ErrorInfo::new( + t!(RETURN_SHOULD_IN_FUNCTION), + t!(SYNTAX_ERROR), + )); + } + // ignore the result + // for return and return expr both + self.expr(true).ok(); + self.add_bycode(Opcode::PopFrame, NO_ARG); + return Ok(()); + } TokenType::Func => { self.def_func()?; return Ok(()); @@ -845,23 +861,17 @@ impl<'a> AstBuilder<'a> { for i in body.iter().rev() { self.token_lexer.next_back(i.0.clone()); } - let mut is_pop = false; loop { let t = self.token_lexer.next_token()?; if t.tp == RightBigBrace { break; } - is_pop = false; - if t.tp == TokenType::Return { - self.expr(false)?; - self.add_bycode(Opcode::PopFrame, NO_ARG); - is_pop = true; - } else { - self.token_lexer.next_back(t); - self.statement()?; - } + self.token_lexer.next_back(t); + self.statement()?; } - if !is_pop { + if !self.staticdata.inst.is_empty() + && self.staticdata.inst.last().unwrap().opcode != Opcode::PopFrame + { self.add_bycode(Opcode::PopFrame, NO_ARG); } self.generate_func_in_scope()?; @@ -1060,6 +1070,34 @@ mod tests { ); } + #[test] + fn test_expr_in_arg() { + gen_test_env!( + r#" +a:=90 +print("{}", a+90)"#, + t + ); + t.generate_code().unwrap(); + assert_eq!( + t.staticdata.inst, + vec![ + Inst::new(Opcode::LoadInt, 2), + Inst::new(Opcode::StoreGlobalInt, get_offset(0)), + Inst::new(Opcode::LoadString, 0), + Inst::new(Opcode::LoadGlobalVarInt, get_offset(0)), + Inst::new(Opcode::LoadInt, 2), + Inst::new(Opcode::AddInt, NO_ARG), + Inst::new(Opcode::MoveInt, NO_ARG), + Inst::new(Opcode::LoadInt, INT_VAL_POOL_ONE), + Inst::new( + Opcode::CallNative, + get_prelude_function("print").unwrap().buildin_id + ), + ] + ) + } + #[test] fn test_call_builtin_function() { gen_test_env!(r#"print("hello world!")"#, t); diff --git a/src/compiler/ast/ast_base.rs b/src/compiler/ast/ast_base.rs index fd6d46f8..9daab029 100644 --- a/src/compiler/ast/ast_base.rs +++ b/src/compiler/ast/ast_base.rs @@ -22,16 +22,12 @@ impl<'a> AstBuilder<'a> { self.first_func = false } - pub fn report_error(&self, info: ErrorInfo) -> AstError { - self.token_lexer.compiler_data.report_compiler_error(info) - } - #[inline] pub fn try_err(&self, istry: bool, info: ErrorInfo) -> AstError { if istry { Err(LightFakeError::new().into()) } else { - self.report_error(info) + self.gen_error(info) } } @@ -116,12 +112,13 @@ impl<'a> AstBuilder<'a> { } pub fn gen_error(&self, e: ErrorInfo) -> AstError { - self.try_err(false, e) + self.token_lexer.compiler_data.report_compiler_error(e) } pub fn get_token_checked(&mut self, ty: TokenType) -> AstError { let t = self.token_lexer.next_token()?; if t.tp != ty { + self.token_lexer.next_back(t.clone()); self.gen_error(ErrorInfo::new( t!(UNEXPECTED_TOKEN, "0" = t.tp), t!(SYNTAX_ERROR), diff --git a/src/tools/dis.rs b/src/tools/dis.rs index 8398d9df..37bc7ba9 100644 --- a/src/tools/dis.rs +++ b/src/tools/dis.rs @@ -5,12 +5,12 @@ pub fn dis(opt: crate::compiler::Option) -> RunResult<()> { let mut compiler = crate::compiler::Compiler::new(opt); let mut ast = compiler.lex()?; let static_data = ast.prepare_get_static(); - for i in &static_data.inst { - print!("{}", i); - match i.opcode { - LoadInt => print!("({})", static_data.constpool.intpool[i.operand]), - LoadString => print!("({})", static_data.constpool.stringpool[i.operand]), - LoadFloat => print!("({})", static_data.constpool.floatpool[i.operand]), + for i in static_data.inst.iter().enumerate() { + print!("{} {}", i.0, i.1); + match i.1.opcode { + LoadInt => print!("({})", static_data.constpool.intpool[i.1.operand]), + LoadString => print!("({})", static_data.constpool.stringpool[i.1.operand]), + LoadFloat => print!("({})", static_data.constpool.floatpool[i.1.operand]), _ => {} } println!(); diff --git a/src/tvm.rs b/src/tvm.rs index d045de0f..d94aaa87 100644 --- a/src/tvm.rs +++ b/src/tvm.rs @@ -523,6 +523,7 @@ impl<'a> Vm<'a> { let condit = impl_opcode!(bool, self, 1); if !condit { *pc = self.static_data.inst[*pc].operand; + return Ok(()); } } Opcode::Jump => {