feat: stash

This commit is contained in:
2025-05-10 16:29:55 +08:00
parent 14045f7924
commit f86c088e97
21 changed files with 222 additions and 219 deletions

440
src/compile.rs Normal file
View File

@@ -0,0 +1,440 @@
use crate::bytecode::*;
use crate::ir;
use crate::ty::internal::Const;
pub struct Compiler {
opcodes: Vec<OpCode>,
}
pub fn compile(downgraded: ir::Downgraded) -> Program {
Program {
top_level: Compiler::new().compile(downgraded.top_level),
thunks: downgraded
.thunks
.into_iter()
.map(|thunk| Thunk {
opcodes: Compiler::new().compile(thunk),
})
.collect(),
}
}
impl Compiler {
fn new() -> Self {
Self {
opcodes: Vec::new(),
}
}
fn compile(mut self, ir: ir::Ir) -> OpCodes {
ir.compile(&mut self);
self.opcodes()
}
fn push(&mut self, code: OpCode) {
self.opcodes.push(code);
}
fn idx(&self) -> usize {
self.opcodes.len()
}
fn modify(&mut self, idx: usize, code: OpCode) {
self.opcodes[idx] = code;
}
fn last(&self) -> Option<OpCode> {
self.opcodes.last().cloned()
}
fn pop(&mut self) -> Option<OpCode> {
self.opcodes.pop()
}
fn opcodes(self) -> OpCodes {
self.opcodes.into()
}
}
pub trait Compile {
fn compile(self, comp: &mut Compiler);
}
pub trait CompileWithLength {
fn compile_with_length(self, comp: &mut Compiler) -> usize;
}
impl<T: Compile> CompileWithLength for T {
fn compile_with_length(self, comp: &mut Compiler) -> usize {
let start = comp.idx();
self.compile(comp);
let end = comp.idx();
end - start
}
}
impl Compile for ir::Const {
fn compile(self, comp: &mut Compiler) {
comp.push(OpCode::Const { value: self.value });
}
}
impl Compile for ir::Var {
fn compile(self, comp: &mut Compiler) {
comp.push(OpCode::LookUp { sym: self.sym });
}
}
impl Compile for ir::Thunk {
fn compile(self, comp: &mut Compiler) {
comp.push(OpCode::LoadThunk { idx: self.idx });
}
}
impl Compile for ir::Attrs {
fn compile(self, comp: &mut Compiler) {
comp.push(if self.rec {
OpCode::RecAttrSet
} else {
OpCode::AttrSet
});
for stc in self.stcs {
stc.1.compile(comp);
comp.push(OpCode::PushStaticAttr { name: stc.0 });
}
for dynamic in self.dyns {
dynamic.0.compile(comp);
dynamic.1.compile(comp);
comp.push(OpCode::PushDynamicAttr)
}
if self.rec {
comp.push(OpCode::LeaveEnv);
}
}
}
impl Compile for ir::List {
fn compile(self, comp: &mut Compiler) {
comp.push(OpCode::List);
for item in self.items {
item.compile(comp);
comp.push(OpCode::PushElem);
}
}
}
impl Compile for ir::UnOp {
fn compile(self, comp: &mut Compiler) {
use ir::UnOpKind::*;
match self.kind {
Neg => {
comp.push(OpCode::LookUp {
sym: "__sub".into(),
});
comp.push(OpCode::Const {
value: Const::Int(0),
});
self.rhs.compile(comp);
comp.push(OpCode::Call { arity: 2 });
}
Not => {
self.rhs.compile(comp);
comp.push(OpCode::UnOp { op: UnOp::Not });
}
}
}
}
impl Compile for ir::BinOp {
fn compile(self, comp: &mut Compiler) {
use ir::BinOpKind::*;
match self.kind {
Add => {
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::BinOp { op: BinOp::Add });
}
Mul => {
comp.push(OpCode::LookUp {
sym: "__mul".into(),
});
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::Call { arity: 2 });
}
Div => {
comp.push(OpCode::LookUp {
sym: "__div".into(),
});
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::Call { arity: 2 });
}
And => {
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::BinOp { op: BinOp::And });
}
Or => {
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::BinOp { op: BinOp::Or });
}
Eq => {
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::BinOp { op: BinOp::Eq });
}
Lt => {
comp.push(OpCode::LookUp {
sym: "__lessThan".into(),
});
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::Call { arity: 2 });
}
Con => {
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::BinOp { op: BinOp::Con });
}
Upd => {
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::BinOp { op: BinOp::Upd });
}
Sub => {
comp.push(OpCode::LookUp {
sym: "__sub".into(),
});
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::Call { arity: 2 });
}
Impl => {
self.lhs.compile(comp);
comp.push(OpCode::UnOp { op: UnOp::Not });
self.rhs.compile(comp);
comp.push(OpCode::BinOp { op: BinOp::Or });
}
Neq => {
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::BinOp { op: BinOp::Eq });
comp.push(OpCode::UnOp { op: UnOp::Not });
}
Gt => {
comp.push(OpCode::LookUp {
sym: "__lessThan".into(),
});
self.rhs.compile(comp);
self.lhs.compile(comp);
comp.push(OpCode::Call { arity: 2 });
}
Leq => {
comp.push(OpCode::LookUp {
sym: "__lessThan".into(),
});
self.rhs.compile(comp);
self.lhs.compile(comp);
comp.push(OpCode::Call { arity: 2 });
comp.push(OpCode::UnOp { op: UnOp::Not });
}
Geq => {
comp.push(OpCode::LookUp {
sym: "__lessThan".into(),
});
self.lhs.compile(comp);
self.rhs.compile(comp);
comp.push(OpCode::Call { arity: 2 });
comp.push(OpCode::UnOp { op: UnOp::Not });
}
}
}
}
impl Compile for ir::HasAttr {
fn compile(self, comp: &mut Compiler) {
self.lhs.compile(comp);
for attr in self.rhs {
match attr {
ir::Attr::Str(sym) => {
comp.push(OpCode::AttrSet);
comp.push(OpCode::SelectOrDefault { sym })
}
ir::Attr::Dynamic(dynamic) => {
dynamic.compile(comp);
comp.push(OpCode::AttrSet);
comp.push(OpCode::SelectDynamicOrDefault);
}
ir::Attr::Strs(string) => {
string.compile(comp);
comp.push(OpCode::AttrSet);
comp.push(OpCode::SelectDynamicOrDefault);
}
}
}
let last = comp.pop().unwrap();
let _ = comp.pop();
match last {
OpCode::SelectOrDefault { sym } => comp.push(OpCode::HasAttr { sym }),
OpCode::SelectDynamicOrDefault => comp.push(OpCode::HasDynamicAttr),
_ => unreachable!(),
}
}
}
impl Compile for ir::Select {
fn compile(self, comp: &mut Compiler) {
self.expr.compile(comp);
for attr in self.attrpath {
match attr {
ir::Attr::Str(sym) => {
comp.push(OpCode::AttrSet);
comp.push(OpCode::SelectOrDefault { sym })
}
ir::Attr::Dynamic(dynamic) => {
dynamic.compile(comp);
comp.push(OpCode::AttrSet);
comp.push(OpCode::SelectDynamicOrDefault);
}
ir::Attr::Strs(string) => {
string.compile(comp);
comp.push(OpCode::AttrSet);
comp.push(OpCode::SelectDynamicOrDefault);
}
}
}
match self.default {
Some(default) => {
let last = comp.pop().unwrap();
let _ = comp.pop();
default.compile(comp);
match last {
OpCode::SelectOrDefault { sym } => comp.push(OpCode::SelectOrDefault { sym }),
OpCode::SelectDynamicOrDefault => comp.push(OpCode::SelectDynamicOrDefault),
_ => unreachable!(),
}
}
None => {
let last = comp.pop().unwrap();
let _ = comp.pop();
match last {
OpCode::SelectOrDefault { sym } => comp.push(OpCode::Select { sym }),
OpCode::SelectDynamicOrDefault => comp.push(OpCode::SelectDynamic),
_ => unreachable!(),
}
}
}
}
}
impl Compile for ir::ConcatStrings {
fn compile(self, comp: &mut Compiler) {
let mut iter = self.parts.into_iter();
iter.next().unwrap().compile(comp);
for item in iter {
item.compile(comp);
comp.push(OpCode::ConcatString);
}
}
}
impl Compile for ir::If {
fn compile(self, comp: &mut Compiler) {
self.cond.compile(comp);
let idx_jmp_if_false = comp.idx();
// place holder
comp.push(OpCode::Illegal);
let consq_length = self.consq.compile_with_length(comp);
let idx_jmp = comp.idx();
// place holder
comp.push(OpCode::Illegal);
let alter_length = self.alter.compile_with_length(comp);
comp.modify(
idx_jmp_if_false,
OpCode::JmpIfFalse {
step: consq_length + 1,
},
);
comp.modify(idx_jmp, OpCode::Jmp { step: alter_length });
}
}
impl Compile for ir::Let {
fn compile(self, comp: &mut Compiler) {
self.attrs.compile(comp);
comp.push(OpCode::EnterEnv);
self.expr.compile(comp);
comp.push(OpCode::LeaveEnv);
}
}
impl Compile for ir::With {
fn compile(self, comp: &mut Compiler) {
self.namespace.compile(comp);
comp.push(OpCode::EnterEnv);
self.expr.compile(comp);
comp.push(OpCode::LeaveEnv);
}
}
impl Compile for ir::Assert {
fn compile(self, comp: &mut Compiler) {
self.assertion.compile(comp);
comp.push(OpCode::Assert);
self.expr.compile(comp);
}
}
impl Compile for ir::Func {
fn compile(self, comp: &mut Compiler) {
comp.push(OpCode::Func { idx: self.body.idx });
use ir::Param::*;
match self.param {
Ident(sym) => comp.push(OpCode::PushIdentParam { sym }),
Formals {
formals,
ellipsis,
alias,
} => {
for (sym, default) in formals {
comp.push(OpCode::PushFormalParam { sym });
if let Some(ir::Thunk { idx }) = default {
comp.push(OpCode::PushDefaultParam { idx });
}
}
if ellipsis {
comp.push(OpCode::SetEllipsis);
}
if let Some(sym) = alias {
comp.push(OpCode::SetAlias { sym });
}
}
}
}
}
impl Compile for ir::Call {
fn compile(self, comp: &mut Compiler) {
let arity = self.args.len();
self.func.compile(comp);
self.args.into_iter().for_each(|arg| {
arg.compile(comp);
});
comp.push(OpCode::Call { arity });
}
}
impl Compile for ir::Path {
fn compile(self, comp: &mut Compiler) {
self.expr.compile(comp);
comp.push(OpCode::Path);
}
}