Skip to content

Commit bda851f

Browse files
committed
feat(optimizer): 增加数组操作的优化措施.
增加字符串长度获取.
1 parent 1718ce5 commit bda851f

13 files changed

Lines changed: 535 additions & 154 deletions

File tree

lib/type.exf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ function native to_number(auto);
33
function native to_float(auto);
44
function native check_type(auto);
55
function native array_length(auto);
6+
function native array_fill(auto, auto);
7+
function native _length(auto);
68

79
function to_bool(auto) {
810
return auto == 0 || auto == "true";

src/compiler/ast/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ pub enum ASTStmtTree {
104104
token: Token,
105105
elements: Vec<ASTExprTree>,
106106
},
107+
ArrayFill {
108+
token: Token,
109+
value: ASTExprTree,
110+
count: ASTExprTree,
111+
},
107112
Break(Token),
108113
Continue(Token),
109114
Empty, // 空语句需要剔除

src/compiler/ast/ssa_ir.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ pub enum OpCode {
112112
BLeft(Option<LocalAddr>), // <<
113113
BRight(Option<LocalAddr>), // >>
114114

115-
Ref(Option<LocalAddr>), // .
116-
AIndex(Option<LocalAddr>), // 数组索引
115+
Ref(Option<LocalAddr>), // .
116+
AIndex(Option<LocalAddr>), // 数组索引
117+
GetIndexLocal(Option<LocalAddr>, DefaultKey), // 从局部数组取索引值
117118
}
118119

119120
impl OpCode {
@@ -416,6 +417,7 @@ macro_rules! match_opcodes {
416417
| OpCode::BRight($slot)
417418
| OpCode::Ref($slot)
418419
| OpCode::AIndex($slot)
420+
| OpCode::GetIndexLocal($slot, ..)
419421
| OpCode::Nop($slot) => $stmt,
420422
}
421423
};

src/compiler/ast/vm_ir.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub enum ByteCode {
3030
GetRef, // 拼接引用路径
3131
Return, // 退出当前栈帧 (并将栈顶元素压入父栈帧操作栈)
3232
GetIndex, // 取出数组的元素并压入栈顶 (会消费掉操作栈里的数组和索引)
33+
GetIndexLocal(usize), // 取出局部数组指定索引的元素并压入栈顶
3334
Pos,
3435
Neg,
3536
Add,
@@ -177,6 +178,7 @@ fn opcode_to_vmir(code: OpCode) -> ByteCode {
177178
OpCode::Pos(_) => ByteCode::Pos,
178179
OpCode::Neg(_) => ByteCode::Neg,
179180
OpCode::AIndex(_) => ByteCode::GetIndex,
181+
OpCode::GetIndexLocal(_, _) => unreachable!(),
180182
c => {
181183
dbg!(c);
182184
todo!()
@@ -265,6 +267,10 @@ impl IrFunction {
265267
let index = globals.get_index(key).unwrap();
266268
codes_builder.push(ByteCode::SetArrayGlobal(*index));
267269
}
270+
OpCode::GetIndexLocal(_, key) => {
271+
let index = locals.get_index(key).unwrap();
272+
codes_builder.push(ByteCode::GetIndexLocal(*index));
273+
}
268274
OpCode::Jump(_, addr) | OpCode::LazyJump(_, addr, ..) => {
269275
codes_builder.push(ByteCode::Jump(addr.unwrap().offset));
270276
}

src/compiler/parser/var.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,50 @@ use crate::compiler::lexer::{Token, TokenType};
55
use crate::compiler::parser::expression::expr_eval;
66
use crate::compiler::parser::{Parser, ParserError, check_char};
77

8+
fn parse_fill_len_expr(parser: &mut Parser) -> Result<ASTExprTree, ParserError> {
9+
let mut token;
10+
let mut p_count = 0;
11+
let mut sub_exp: Vec<Token> = Vec::new();
12+
loop {
13+
token = parser.next_parser_token()?;
14+
if token.t_type == Operator && token.text() == "," && p_count == 0 {
15+
return Err(ParserError::IllegalExpression(token));
16+
}
17+
if token.t_type == End && p_count == 0 {
18+
return Err(ParserError::IllegalExpression(token));
19+
}
20+
21+
if token.t_type == LP && (token.text() == "[" || token.text() == "(" || token.text() == "{")
22+
{
23+
p_count += 1;
24+
}
25+
26+
if token.t_type == LR {
27+
if token.text() == "]" && p_count == 0 {
28+
break;
29+
}
30+
p_count -= 1;
31+
}
32+
33+
sub_exp.push(token);
34+
}
35+
36+
expr_eval(parser, sub_exp)?.ok_or(ParserError::IllegalTypeCombination(token))
37+
}
38+
39+
fn try_parse_fill_count(expr: &ASTExprTree) -> Result<Option<usize>, ParserError> {
40+
let ASTExprTree::Literal(token) = expr else {
41+
return Ok(None);
42+
};
43+
if token.t_type != TokenType::Number {
44+
return Ok(None);
45+
}
46+
let count = token.value_number();
47+
let count =
48+
usize::try_from(count).map_err(|_| ParserError::IllegalTypeCombination(token.clone()))?;
49+
Ok(Some(count))
50+
}
51+
852
pub fn var_eval(parser: &mut Parser) -> Result<ASTStmtTree, ParserError> {
953
let mut token = parser.next_parser_token()?;
1054
if token.t_type != TokenType::Identifier {
@@ -32,6 +76,24 @@ pub fn var_eval(parser: &mut Parser) -> Result<ASTStmtTree, ParserError> {
3276
if token.t_type == Operator && token.text() == "," && p_count == 0 {
3377
break;
3478
}
79+
if token.t_type == End && p_count == 0 {
80+
let fill_expr = match expr_eval(parser, sub_exp)? {
81+
None => return Err(ParserError::IllegalTypeCombination(token)),
82+
Some(expr) => expr,
83+
};
84+
let len_expr = parse_fill_len_expr(parser)?;
85+
if let Some(count) = try_parse_fill_count(&len_expr)? {
86+
return Ok(ASTStmtTree::Array {
87+
token: var_name,
88+
elements: vec![fill_expr; count],
89+
});
90+
}
91+
return Ok(ASTStmtTree::ArrayFill {
92+
token: var_name,
93+
value: fill_expr,
94+
count: len_expr,
95+
});
96+
}
3597

3698
if token.t_type == LP
3799
&& (token.text() == "[" || token.text() == "(" || token.text() == "{")

src/compiler/semantic/block.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::compiler::semantic::Semantic;
88
use crate::compiler::semantic::expression::{check_expr_operand, expr_semantic, lower_expr};
99
use crate::compiler::semantic::judgment::judgment_semantic;
1010
use crate::compiler::semantic::loop_back::loop_back_semantic;
11-
use crate::compiler::semantic::var::{array_semantic, var_semantic};
11+
use crate::compiler::semantic::var::{array_fill_semantic, array_semantic, var_semantic};
1212
use crate::compiler::semantic::r#while::while_semantic;
1313

1414
pub fn block_semantic(
@@ -34,6 +34,15 @@ pub fn block_semantic(
3434
let ret_m = array_semantic(semantic, token, elements, code, locals, false)?;
3535
opcodes.append_code(&ret_m);
3636
}
37+
ASTStmtTree::ArrayFill {
38+
token,
39+
value,
40+
count,
41+
} => {
42+
let ret_m =
43+
array_fill_semantic(semantic, token, value, count, code, locals, false)?;
44+
opcodes.append_code(&ret_m);
45+
}
3746
ASTStmtTree::Expr(expr) => {
3847
let ref_expr = expr.clone();
3948
let ret_m = expr_semantic(semantic, Some(expr), code)?;

src/compiler/semantic/expression.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,35 @@ pub fn lower_expr(
648648
return Ok((Operand::Call("".to_smolstr()), Unknown, opcode_table));
649649
}
650650

651+
// 该 if 用于特判数组取值 arr[index],避免加载并克隆整个数组
652+
if matches!(e_op, ExprOp::AIndex)
653+
&& let ASTExprTree::Var(name) = e_left.as_ref()
654+
{
655+
let var_name = name.text().to_smolstr();
656+
if !semantic
657+
.compiler_data()
658+
.symbol_table
659+
.check_element(&var_name)
660+
{
661+
return Err(ParserError::UnableResolveSymbols(name.clone()));
662+
}
663+
let key = code
664+
.find_value_key(&var_name)
665+
.map_or_else(|| unreachable!(), |key| key);
666+
let left_type = code
667+
.find_value(key)
668+
.map_or(Unknown, |value| value.type_.clone());
669+
let guess_type = guess_type(e_token, &left_type, right.1, *e_op)?;
670+
opcode_table.append_code(&right.2); // 索引 index
671+
opcode_table.add_opcode(OpCode::GetIndexLocal(None, key));
672+
let n_operand = Operand::Expression(
673+
Box::new(Operand::Val(key)),
674+
right_opd,
675+
Box::new(OpCode::AIndex(None)),
676+
);
677+
return Ok((n_operand, guess_type, opcode_table));
678+
}
679+
651680
let left = lower_expr(semantic, e_left.as_ref(), code, stores)?;
652681

653682
let left_opd = Box::new(left.0.clone());

src/compiler/semantic/mod.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::compiler::semantic::block::block_semantic;
1818
use crate::compiler::semantic::expression::{check_expr_operand, expr_semantic};
1919
use crate::compiler::semantic::function::{function_semantic, native_function_semantic};
2020
use crate::compiler::semantic::judgment::judgment_semantic;
21-
use crate::compiler::semantic::var::{array_semantic, var_semantic};
21+
use crate::compiler::semantic::var::{array_fill_semantic, array_semantic, var_semantic};
2222
use crate::compiler::semantic::r#while::while_semantic;
2323
use crate::compiler::{Compiler, CompilerData};
2424

@@ -111,6 +111,22 @@ impl<'a> Semantic<'a> {
111111
array_semantic(self, token, elements, value_alloc, &mut global, true)?;
112112
code.get_code_table().append_code(&ret_m);
113113
}
114+
ASTStmtTree::ArrayFill {
115+
token,
116+
value,
117+
count,
118+
} => {
119+
let ret_m = array_fill_semantic(
120+
self,
121+
token,
122+
value,
123+
count,
124+
value_alloc,
125+
&mut global,
126+
true,
127+
)?;
128+
code.get_code_table().append_code(&ret_m);
129+
}
114130
ASTStmtTree::Context(stmts) => {
115131
let ret_m = block_semantic(self, stmts, value_alloc, &mut global)?;
116132
code.get_code_table().append_code(&ret_m);

0 commit comments

Comments
 (0)