mimium

ツリー形式から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)=>{
	   
	 }
	}
 
}