wip: converting expressions -> instructions.
This commit is contained in:
parent
80b7ec77a3
commit
1975271d15
3 changed files with 124 additions and 2 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -187,6 +187,7 @@ impl Type {
|
|||
| Type::Float
|
||||
| Type::Array
|
||||
| Type::Map
|
||||
| Type::String
|
||||
) || self.predicate(|t| t.is_native())
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue