wip: converting expressions -> instructions.

This commit is contained in:
James Harton 2022-10-01 19:03:26 +13:00
parent 80b7ec77a3
commit 1975271d15
3 changed files with 124 additions and 2 deletions

View file

@ -53,7 +53,31 @@ pub enum Type {
#[derive(Debug, Clone)]
pub struct Block {
pub instructions: Vec<Instruction>,
pub arguments: Vec<UniqueVecKey<Type>>,
pub instructions: IndexedVec<Instruction>,
}
impl Block {
pub fn is_terminated(&self) -> bool {
self.instructions
.as_slice()
.last()
.map(Instruction::is_terminal)
.unwrap_or(false)
}
pub fn push(&mut self, instruction: Instruction) -> IndexedVecKey<Instruction> {
self.instructions.insert(instruction)
}
}
impl Default for Block {
fn default() -> Self {
Self {
arguments: Vec::new(),
instructions: IndexedVec::new(),
}
}
}
#[derive(Debug, Clone)]
@ -100,3 +124,9 @@ pub enum Instruction {
/// Pops a value off the stack and stores in in the local variable scope.
SetLocal(UniqueVecKey<String>),
}
impl Instruction {
pub fn is_terminal(&self) -> bool {
matches!(self, Instruction::Return)
}
}

View file

@ -2,6 +2,8 @@ use crate::ir;
use crate::{Source, Span};
use outrun_bytecode as bc;
use outrun_common::{IndexedVec, IndexedVecKey, UniqueVec, UniqueVecKey};
use std::collections::HashMap;
use std::iter::once;
use std::sync::Arc;
pub fn into_bytecode(context: &mut ir::Context) -> Result<Vec<bc::Module>, ir::Error> {
@ -78,6 +80,12 @@ fn into_function(
let name = fun.name.clone();
// look for guards, to build entry block, otherwise just jump direct to the body.
let block_id = if fun.has_body() {
let block_id = into_block(fun.body.borrow().clone(), module, arguments.clone())?;
Some(block_id)
} else {
None
};
let entry = if fun.is_prototype() {
None
@ -87,7 +95,7 @@ fn into_function(
None
} else {
// just jump directly to the body.
None
block_id
}
};
@ -104,6 +112,89 @@ fn into_function(
Ok(idx)
}
fn into_block(
body: Vec<ir::Expression>,
module: &mut bc::Module,
arguments: Vec<(UniqueVecKey<String>, UniqueVecKey<bc::Type>)>,
) -> Result<IndexedVecKey<bc::Block>, ir::Error> {
let mut block = bc::Block::default();
let mut locals = arguments.iter().cloned().collect();
collect_expressions(body, &mut block, &mut locals, module)?;
if !block.is_terminated() {
block.push(bc::Instruction::Return);
}
let block_id = module.blocks.insert(block);
Ok(block_id)
}
fn collect_expressions(
body: Vec<ir::Expression>,
block: &mut bc::Block,
locals: &mut HashMap<UniqueVecKey<String>, UniqueVecKey<bc::Type>>,
module: &mut bc::Module,
) -> Result<(), ir::Error> {
for expr in body {
match expr.value {
ir::ExpressionValue::Array(values) => {
collect_expressions(values.clone(), block, locals, module)?;
block.push(bc::Instruction::CreateArray(values.len()));
}
ir::ExpressionValue::Atom(value) => {
let value = module.strings.insert(value);
block.push(bc::Instruction::PushAtom(value));
}
ir::ExpressionValue::Boolean(value) => {
block.push(bc::Instruction::PushBoolean(value));
}
ir::ExpressionValue::Constructor(values) => {
collect_expressions(values.clone(), block, locals, module)?;
let ty = into_type(expr.r#type, &mut module.types, &mut module.strings)?;
block.push(bc::Instruction::Construct(ty, values.len()));
}
ir::ExpressionValue::Float(value) => {
block.push(bc::Instruction::PushFloat(value));
}
ir::ExpressionValue::GetLocal(name) => {
// FIXME yeah so we need to do locals.
}
ir::ExpressionValue::Index { .. } => {
// FIXME
}
ir::ExpressionValue::Integer(value) => {
block.push(bc::Instruction::PushInteger(value));
}
ir::ExpressionValue::Let { .. } => {
// FIXME
}
ir::ExpressionValue::LocalCall { .. } => {
// FIXME
}
ir::ExpressionValue::Map(values) => {
let values: Vec<ir::Expression> = values
.iter()
.flat_map(|(key, value)| once(key).chain(once(value)))
.cloned()
.collect();
collect_expressions(values.clone(), block, locals, module)?;
block.push(bc::Instruction::CreateMap(values.len()));
}
ir::ExpressionValue::RemoteCall { .. } => {
// FIXME wat.
}
ir::ExpressionValue::String(value) => {
let value = module.strings.insert(value);
block.push(bc::Instruction::PushString(value));
}
}
}
Ok(())
}
fn into_source_location(
source: Option<Arc<Source>>,
span: Option<Span>,

View file

@ -187,6 +187,7 @@ impl Type {
| Type::Float
| Type::Array
| Type::Map
| Type::String
) || self.predicate(|t| t.is_native())
}