ツリー形式からBasicBlockのインストラクション形式に変える
Stateのこととupvalueを両方処理しなくてはならない。ワンパスで処理できるのか?
StateSize計算とUpvalue計算の両方をtraitとして切り出す方がいいのかな
値
結局W計算のStaged Interpreterと変わらんかもな
そうすると型付けの時点でクロージャ相当の項とグローバル関数適用の項は分かれることになる?エフェクトとして考えるのが妥当なのかな
型
コンパイル
Valueとして、次のようなものがあり得る
struct VRegister(usize);//Vregisterは無限に使用できてサイズ可変
struct StackSlot(usize);
enum Value{
Static(usize),
Global(usize),
Function(usize),
ExternalItem(usize),
Register(VRegister),
StackSlot(StackSlot),//引数とかはこれで処理して良い
}
原則、Letが出てくればStackSlotに確保、そうでない一次変数はRegisterに確保でよい LetだけどRegisterに逃がせるとか、RegisterからStackへスピルするとかはオプティマイザの範疇 基本的にはFuncProtoはValueに依存しない構造にしたい
今はmir::ValueにmirgenとBytecodeGen両方が依存しているが、Valueは本来Expr→MIR生成時に使われるだけの中間的な値であるべき
struct MIR{
name:Symbol,
static_data:Vec<StaticData>
externals:<ExternalItems>
functions:Vec<FuncProto>
}
struct Operation{
dest:Option<VRegister>,
inst:Instruction
}
struct UpIndex(FnId,usize)
struct UpIndexStorage(Vec<StackSlot>)
impl UpIndexStorage{
fn get_upv_index(&self,i:UpIndex)->Option<StackSlot>{
self.0.get(i.0)
}
}
struct BlockId(usize)
struct BasicBlock{
label:Symbol,
entry_v:Vec<BlockId>
op:Vec<Operation>
}
struct BlockChunk(Vec<Block>)
impl BlockChunk{ /*newtype pattern*/ }
struct FuncProto{
name: Symbol,
upindexes: UpIndexStorage,
blocks: BlockChunk,
state_tree: Vec<StateLeaf> //StateTreeは実際のデータを保持しない
meta_labels:BTreeMap<StackSlot,Symbol> //print用メタデータ
}
enum Instruction{
Load(StackSlot,Type)
Store{dest:StackSlot,src:Register,Type},
GetUpValue(UpIndex,Type),
JmpIf{cond:Register,then:BlockId,else_:BlockId,merge:BlockId},
ShiftStatePos(isize)//ツリーの子インデックスに対するカーソル移動オフセット
GetState(Type)
//その他、プリミティブな命令はfrom Register to Register
}
評価をしながら副作用としてMIRを書き込んでいくような感じ
fn eval(e:ExprNodeId,env:Env<(Value,Type)>)->(Value,Type){
match e.to_expr() {
Expr::Id(name)=>{
match env.lookup(name){
(Value::Register(r),t)=>(r,t)
(Value::StackSlot(s),t)=>push_inst(Instruction::Load(s,t))
}
},
Expr::Let(name,e,body)=>{
let env = env.extend((name,eval(e,env).0));
eval(e,env)
},
Expr::App(e,args)=>{
let (f,ft) = eval(e,env);
let argvs = args.iter().map(|e| eval(e,env));
match f{
Value::Closure(fproto,names,body,env)=>{
let kvs = names.iter().zip(argvs.zip()).collect()
let env = env.extend(kvs);
eval(body,env)
}
_=>panic!()
}
}
Expr::Feed(id,body)=>{
}
}
}