Skip to content

Commit ad27dd9

Browse files
committed
feat(semantic): 支持跳转指令, 增加循环语句转义.
修复类型推断器无法正确根据运算符推断类型的问题.
1 parent 3c220d7 commit ad27dd9

11 files changed

Lines changed: 530 additions & 148 deletions

File tree

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ smol_str = "0.3.4"
88
slotmap = "1"
99
getopts-macro = "0.1.8"
1010
expect-test = "1.5.1"
11+
linked-hash-map = "0.5.6"
1112

1213
[profile.release]
1314
debug = false

src/compiler/ast/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub enum ASTStmtTree {
7777
Import(Token), // import "library";
7878
Context(Vec<ASTStmtTree>), // 独立上下文
7979
Loop {
80+
token: Token,
8081
cond: ASTExprTree,
8182
body: Vec<ASTStmtTree>,
8283
},

src/compiler/ast/ssa_ir.rs

Lines changed: 222 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
use crate::compiler::lexer::Token;
22
use slotmap::{DefaultKey, SlotMap};
33
use smol_str::SmolStr;
4+
use std::collections::HashMap;
5+
use linked_hash_map::LinkedHashMap;
6+
7+
#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
8+
pub struct LocalAddr {
9+
pub offset: usize,
10+
}
411

512
#[derive(Clone, Debug, PartialEq)]
613
pub enum Operand {
@@ -34,51 +41,164 @@ pub struct Value {
3441
}
3542

3643
#[derive(Clone, Debug, PartialEq)]
37-
#[allow(dead_code)] //TODO
44+
#[allow(dead_code)] // TODO
3845
pub enum OpCode {
39-
StackLocal(DefaultKey, Operand), // 栈局部变量加载
40-
StoreLocal(DefaultKey, Operand), // 将一个变量加载到栈顶
41-
Push(Operand), // 将值压入操作栈
42-
Call(SmolStr), // 函数调用 (调用路径) : 只能被 Ref 操作触发
43-
Return, // 栈顶结果返回
44-
Add, // 从栈顶提取两个操作数相加并将结果压回操作栈
45-
Sub, // -
46-
Mul, // *
47-
Div, // /
48-
And, // &&
49-
Or, // ||
50-
Rmd, // %
51-
Equ, // ==
52-
SAdd, // ++
53-
SSub, // --
54-
Not, // !
55-
NotEqu, // !=
56-
BigEqu, // >=
57-
LesEqu, // <=
58-
Big, // >
59-
Less, // <
60-
Store, // =
61-
AddS, // +=
62-
SubS, // -=
63-
MulS, // *=
64-
DivS, // /=
65-
RmdS, // %=
66-
BitAnd, // &
67-
BitOr, // |
68-
BitXor, // ^
69-
BAndS, // &=
70-
BOrS, // |=
71-
BXorS, // ^=
72-
BLeft, // <<
73-
BRight, // >>
74-
Ref, // .
75-
AIndex, // 数组索引
46+
// Option<LocalAddr> 为各 IR 的逻辑地址
47+
StackLocal(Option<LocalAddr>, DefaultKey, Operand), // 栈局部变量加载
48+
StoreLocal(Option<LocalAddr>, DefaultKey, Operand), // 将一个变量加载到栈顶
49+
Push(Option<LocalAddr>, Operand), // 将值压入操作栈
50+
Call(Option<LocalAddr>, SmolStr), // 函数调用
51+
Jump(Option<LocalAddr>, LocalAddr), // 无条件跳转
52+
JumpTrue(Option<LocalAddr>, Option<LocalAddr>, Operand), // 栈顶结果为真则跳转
53+
Return(Option<LocalAddr>), // 栈顶结果返回
54+
Break(Option<LocalAddr>), // 退出循环
55+
Continue(Option<LocalAddr>), // 取消本次循环
56+
Nop(Option<LocalAddr>), // 空操作
57+
58+
Add(Option<LocalAddr>), // +
59+
Sub(Option<LocalAddr>), // -
60+
Mul(Option<LocalAddr>), // *
61+
Div(Option<LocalAddr>), // /
62+
And(Option<LocalAddr>), // &&
63+
Or(Option<LocalAddr>), // ||
64+
Rmd(Option<LocalAddr>), // %
65+
66+
Equ(Option<LocalAddr>), // ==
67+
NotEqu(Option<LocalAddr>), // !=
68+
BigEqu(Option<LocalAddr>), // >=
69+
LesEqu(Option<LocalAddr>), // <=
70+
Big(Option<LocalAddr>), // >
71+
Less(Option<LocalAddr>), // <
72+
73+
SAdd(Option<LocalAddr>), // ++
74+
SSub(Option<LocalAddr>), // --
75+
76+
Not(Option<LocalAddr>), // !
77+
78+
Store(Option<LocalAddr>), // =
79+
AddS(Option<LocalAddr>), // +=
80+
SubS(Option<LocalAddr>), // -=
81+
MulS(Option<LocalAddr>), // *=
82+
DivS(Option<LocalAddr>), // /=
83+
RmdS(Option<LocalAddr>), // %=
84+
85+
BitAnd(Option<LocalAddr>), // &
86+
BitOr(Option<LocalAddr>), // |
87+
BitXor(Option<LocalAddr>), // ^
88+
89+
BAndS(Option<LocalAddr>), // &=
90+
BOrS(Option<LocalAddr>), // |=
91+
BXorS(Option<LocalAddr>), // ^=
92+
93+
BLeft(Option<LocalAddr>), // <<
94+
BRight(Option<LocalAddr>), // >>
95+
96+
Ref(Option<LocalAddr>), // .
97+
AIndex(Option<LocalAddr>), // 数组索引
98+
}
99+
100+
impl OpCode {
101+
fn relocate_addr(&mut self, addr_map: &HashMap<LocalAddr, LocalAddr>) {
102+
// 重定位第一个字段:Option<LocalAddr>
103+
if let Some(new_addr) = addr_map.get(&self.get_id()) {
104+
self.set_id(*new_addr);
105+
}
106+
107+
// 重定位 Jump 和 JumpTrue 的跳转目标
108+
match self {
109+
OpCode::Jump(_, target_addr) => {
110+
if let Some(new_addr) = addr_map.get(target_addr) {
111+
*target_addr = *new_addr;
112+
}
113+
}
114+
OpCode::JumpTrue(_, target, ..) => {
115+
if let Some(j_target) = target
116+
&& let Some(&new_target) = addr_map.get(j_target)
117+
{
118+
*target = Some(new_target);
119+
}
120+
}
121+
// 其他 OpCode 没有额外的 LocalAddr 字段
122+
_ => {}
123+
}
124+
}
76125
}
77126

78-
#[derive(Clone, Debug)]
127+
#[derive(Debug, PartialEq, Clone)]
128+
pub struct OpCodeTable {
129+
opcodes: LinkedHashMap<LocalAddr, OpCode>,
130+
alloc_addr: LocalAddr,
131+
}
132+
133+
impl OpCodeTable {
134+
pub fn new() -> Self {
135+
OpCodeTable {
136+
opcodes: LinkedHashMap::new(),
137+
alloc_addr: LocalAddr { offset: 0 },
138+
}
139+
}
140+
141+
pub fn add_opcode(&mut self, opcode: OpCode) -> LocalAddr {
142+
let addr = self.alloc_addr;
143+
self.opcodes.insert(addr, opcode);
144+
self.alloc_addr.offset += 1;
145+
if let Some(op) = self.opcodes.get_mut(&addr) {
146+
op.set_id(addr);
147+
} else {
148+
unreachable!()
149+
}
150+
addr
151+
}
152+
153+
// 返回IR块最后一条IR的逻辑地址
154+
pub fn append_code(&mut self, code: &mut OpCodeTable) -> (LocalAddr,Option<LocalAddr>) {
155+
let start_offset = self.alloc_addr.offset;
156+
if code.opcodes.is_empty() {
157+
return (LocalAddr {
158+
offset: self.alloc_addr.offset,
159+
},None);
160+
}
161+
let mut old_to_new: HashMap<LocalAddr, LocalAddr> = HashMap::new();
162+
163+
// 遍历所有 opcode(按 offset 顺序)
164+
let mut entries: Vec<_> = code.opcodes.iter().collect();
165+
entries.sort_unstable_by_key(|&(addr, _)| addr.offset);
166+
167+
// 为每个旧地址分配新地址
168+
for (old_addr, _) in &entries {
169+
let od = **old_addr;
170+
old_to_new.insert(
171+
od,
172+
LocalAddr {
173+
offset: self.alloc_addr.offset,
174+
},
175+
);
176+
self.alloc_addr.offset += 1;
177+
}
178+
179+
// 插入并重定位
180+
let mut last_addr = None;
181+
for (old_addr, op) in entries {
182+
let mut new_op = op.clone();
183+
new_op.relocate_addr(&old_to_new);
184+
185+
let new_addr = old_to_new[old_addr];
186+
self.opcodes.insert(new_addr, new_op);
187+
last_addr = Some(new_addr);
188+
}
189+
190+
(LocalAddr{offset:start_offset},last_addr)
191+
}
192+
193+
pub fn find_code_mut(&mut self, key: LocalAddr) -> Option<&mut OpCode> {
194+
self.opcodes.get_mut(&key)
195+
}
196+
}
197+
198+
#[derive(Debug, Clone)]
79199
#[allow(dead_code)] //TODO
80200
pub struct Code {
81-
codes: Vec<OpCode>,
201+
codes: OpCodeTable,
82202
values: SlotMap<DefaultKey, Value>,
83203
stack_size: usize,
84204
root: bool, // 是否是根脚本上下文 (true: 根上下文|false: 函数上下文)
@@ -87,19 +207,15 @@ pub struct Code {
87207
impl Code {
88208
pub fn new(root: bool) -> Code {
89209
Self {
90-
codes: vec![],
210+
codes: OpCodeTable::new(),
91211
values: SlotMap::new(),
92212
stack_size: 0,
93213
root,
94214
}
95215
}
96216

97-
pub fn add_opcode(&mut self, opcode: OpCode) {
98-
self.codes.push(opcode);
99-
}
100-
101-
pub fn append_code(&mut self, code: &mut Vec<OpCode>) {
102-
self.codes.append(code);
217+
pub fn get_code_table(&mut self) -> &mut OpCodeTable {
218+
&mut self.codes
103219
}
104220

105221
pub fn find_value_key(&mut self, name: SmolStr) -> Option<DefaultKey> {
@@ -124,3 +240,62 @@ impl Code {
124240
self.values.insert(va)
125241
}
126242
}
243+
244+
macro_rules! mathch_opcodes {
245+
($expr: expr,$slot:ident,$stmt: expr) => {
246+
match $expr {
247+
OpCode::StackLocal($slot, ..)
248+
| OpCode::StoreLocal($slot, ..)
249+
| OpCode::Push($slot, ..)
250+
| OpCode::Call($slot, ..)
251+
| OpCode::Jump($slot, ..)
252+
| OpCode::JumpTrue($slot, ..)
253+
| OpCode::Return($slot)
254+
| OpCode::Break($slot)
255+
| OpCode::Continue($slot)
256+
| OpCode::Add($slot)
257+
| OpCode::Sub($slot)
258+
| OpCode::Mul($slot)
259+
| OpCode::Div($slot)
260+
| OpCode::And($slot)
261+
| OpCode::Or($slot)
262+
| OpCode::Rmd($slot)
263+
| OpCode::Equ($slot)
264+
| OpCode::NotEqu($slot)
265+
| OpCode::BigEqu($slot)
266+
| OpCode::LesEqu($slot)
267+
| OpCode::Big($slot)
268+
| OpCode::Less($slot)
269+
| OpCode::SAdd($slot)
270+
| OpCode::SSub($slot)
271+
| OpCode::Not($slot)
272+
| OpCode::Store($slot)
273+
| OpCode::AddS($slot)
274+
| OpCode::SubS($slot)
275+
| OpCode::MulS($slot)
276+
| OpCode::DivS($slot)
277+
| OpCode::RmdS($slot)
278+
| OpCode::BitAnd($slot)
279+
| OpCode::BitOr($slot)
280+
| OpCode::BitXor($slot)
281+
| OpCode::BAndS($slot)
282+
| OpCode::BOrS($slot)
283+
| OpCode::BXorS($slot)
284+
| OpCode::BLeft($slot)
285+
| OpCode::BRight($slot)
286+
| OpCode::Ref($slot)
287+
| OpCode::AIndex($slot)
288+
| OpCode::Nop($slot) => $stmt,
289+
}
290+
};
291+
}
292+
293+
impl OpCode {
294+
pub fn get_id(&self) -> LocalAddr {
295+
mathch_opcodes!(self, slot, slot).unwrap()
296+
}
297+
298+
pub fn set_id(&mut self, id: LocalAddr) {
299+
mathch_opcodes!(self, slot, *slot = Some(id));
300+
}
301+
}

src/compiler/parser/tests.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ use crate::compiler::{file::SourceFile, parser::Parser};
55
fn parse_source(src: &str) -> Result<crate::compiler::ast::ASTStmtTree, super::ParserError> {
66
let mut file = SourceFile::new("<test_input>".into(), src.into(), Default::default());
77
let parser = Parser::new(&mut file);
8-
let ast = parser.parser();
9-
ast
8+
parser.parser()
109
}
1110

1211
#[track_caller]

src/compiler/parser/while.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use smol_str::SmolStr;
88

99
pub fn while_eval(parser: &mut Parser) -> Result<ASTStmtTree, ParserError> {
1010
let mut token = parser.next_parser_token()?;
11+
let head = token.clone();
1112
let cond: ASTExprTree;
1213

1314
match token.t_type {
@@ -39,5 +40,5 @@ pub fn while_eval(parser: &mut Parser) -> Result<ASTStmtTree, ParserError> {
3940

4041
let body = blk_eval(parser)?;
4142

42-
Ok(ASTStmtTree::Loop { cond, body })
43+
Ok(ASTStmtTree::Loop { token:head,cond, body })
4344
}

0 commit comments

Comments
 (0)