schala/schala-lang/language/src/reduced_ir/mod.rs

234 lines
9.0 KiB
Rust
Raw Normal View History

use crate::ast;
use crate::symbol_table::{DefId, Symbol, SymbolSpec, SymbolTable};
use crate::builtin::Builtin;
use std::str::FromStr;
use std::collections::HashMap;
2021-10-24 15:59:40 -07:00
mod types;
mod test;
2021-10-24 15:59:40 -07:00
pub use types::*;
pub fn reduce(ast: &ast::AST, symbol_table: &SymbolTable) -> ReducedIR {
let reducer = Reducer::new(symbol_table);
reducer.reduce(ast)
}
struct Reducer<'a> {
symbol_table: &'a SymbolTable,
2021-10-24 02:54:21 -07:00
functions: HashMap<DefId, FunctionDefinition>,
}
impl<'a> Reducer<'a> {
fn new(symbol_table: &'a SymbolTable) -> Self {
Self {
symbol_table,
functions: HashMap::new(),
}
}
fn reduce(mut self, ast: &ast::AST) -> ReducedIR {
// First reduce all functions
// TODO once this works, maybe rewrite it using the Visitor
for statement in ast.statements.iter() {
self.top_level_statement(&statement);
}
// Then compute the entrypoint statements (which may reference previously-computed
// functions by ID)
let mut entrypoint = vec![];
for statement in ast.statements.iter() {
let ast::Statement { id: item_id, kind, .. } = statement;
match &kind {
ast::StatementKind::Expression(expr) => {
entrypoint.push(Statement::Expression(self.expression(&expr)));
},
ast::StatementKind::Declaration(ast::Declaration::Binding { name, constant, expr, ..}) => {
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
entrypoint.push(Statement::Binding { id: symbol.def_id.clone(), constant: *constant, expr: self.expression(&expr) });
},
_ => ()
}
}
ReducedIR {
functions: self.functions,
entrypoint,
}
}
fn top_level_statement(&mut self, statement: &ast::Statement) {
let ast::Statement { id: item_id, kind, .. } = statement;
match kind {
ast::StatementKind::Expression(_expr) => {
//TODO expressions can in principle contain definitions, but I won't worry
//about it now
()
},
ast::StatementKind::Declaration(decl) => match decl {
ast::Declaration::FuncDecl(_, statements) => {
self.insert_function_definition(item_id, statements);
},
_ => ()
},
ast::StatementKind::Import(..) => (),
ast::StatementKind::Module(modspec) => {
//TODO handle modules
()
}
}
}
fn function_internal_statement(&mut self, statement: &ast::Statement) -> Option<Statement> {
let ast::Statement { id: item_id, kind, .. } = statement;
match kind {
ast::StatementKind::Expression(expr) => {
Some(Statement::Expression(self.expression(expr)))
},
ast::StatementKind::Declaration(decl) => match decl {
ast::Declaration::FuncDecl(_, statements) => {
self.insert_function_definition(item_id, statements);
None
},
_ => None
},
_ => None
}
}
fn insert_function_definition(&mut self, item_id: &ast::ItemId, statements: &ast::Block) {
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
let def_id = symbol.def_id.clone();
2021-10-24 02:54:21 -07:00
let function_def = FunctionDefinition {
body: self.function(statements)
};
2021-10-24 02:54:21 -07:00
self.functions.insert(def_id, function_def);
}
fn expression(&mut self, expr: &ast::Expression) -> Expression {
use crate::ast::ExpressionKind::*;
use Expression::{Unimplemented};
match &expr.kind {
NatLiteral(n) => Expression::Literal(Literal::Nat(*n)),
FloatLiteral(f) => Expression::Literal(Literal::Float(*f)),
StringLiteral(s) => Expression::Literal(Literal::StringLit(s.clone())),
BoolLiteral(b) => Expression::Literal(Literal::Bool(*b)),
BinExp(binop, lhs, rhs) => self.binop(binop, lhs, rhs),
PrefixExp(op, arg) => self.prefix(op, arg),
Value(qualified_name) => self.value(qualified_name),
2021-10-24 17:57:56 -07:00
Call { f, arguments } => Expression::Call {
f: Box::new(self.expression(f)),
args: arguments
.iter()
.map(|arg| self.invocation_argument(arg))
.collect(),
},
TupleLiteral(exprs) => Expression::Tuple(exprs.iter().map(|e| self.expression(e)).collect()),
IfExpression {
discriminator,
body,
} => Unimplemented, //self.reduce_if_expression(deref_optional_box(discriminator), body),
2021-10-24 18:59:00 -07:00
Lambda { params, body, .. } => {
Expression::Callable(Function::Lambda {
arity: params.len() as u8,
body: self.function(body),
})
},
NamedStruct { name, fields } => Unimplemented, //self.reduce_named_struct(name, fields),
Index { .. } => Unimplemented,
WhileExpression { .. } => Unimplemented,
ForExpression { .. } => Unimplemented,
ListLiteral { .. } => Unimplemented,
}
}
2021-10-24 17:57:56 -07:00
fn invocation_argument(&mut self, invoc: &ast::InvocationArgument) -> Expression {
use crate::ast::InvocationArgument::*;
match invoc {
Positional(ex) => self.expression(ex),
Keyword { .. } => Expression::ReductionError("Keyword arguments not supported".to_string()),
Ignored => Expression::ReductionError("Ignored arguments not supported".to_string()),
}
}
fn function(&mut self, statements: &ast::Block) -> Vec<Statement> {
statements.iter().filter_map(|stmt| self.function_internal_statement(stmt)).collect()
}
fn prefix(&mut self, prefix: &ast::PrefixOp, arg: &ast::Expression) -> Expression {
let builtin: Option<Builtin> = TryFrom::try_from(prefix).ok();
match builtin {
Some(op) => {
Expression::Call {
2021-10-24 02:54:21 -07:00
f: Box::new(Expression::Callable(Function::Builtin(op))),
args: vec![self.expression(arg)],
}
}
None => {
//TODO need this for custom prefix ops
Expression::Unimplemented
}
}
}
fn binop(&mut self, binop: &ast::BinOp, lhs: &ast::Expression, rhs: &ast::Expression) -> Expression {
use Expression::*;
let operation = Builtin::from_str(binop.sigil()).ok();
match operation {
Some(Builtin::Assignment) => {
let lval = match &lhs.kind {
ast::ExpressionKind::Value(qualified_name) => {
if let Some(Symbol { def_id, .. }) = self.symbol_table.lookup_symbol(&qualified_name.id) {
def_id.clone()
} else {
return ReductionError(format!("Couldn't look up name: {:?}", qualified_name));
}
},
_ => return ReductionError("Trying to assign to a non-name".to_string()),
};
Assign {
lval,
rval: Box::new(self.expression(rhs)),
}
},
Some(op) => {
Expression::Call {
2021-10-24 02:54:21 -07:00
f: Box::new(Expression::Callable(Function::Builtin(op))),
args: vec![self.expression(lhs), self.expression(rhs)],
}
}
None => {
//TODO handle a user-defined operation
Unimplemented
}
}
}
fn value(&mut self, qualified_name: &ast::QualifiedName) -> Expression {
2021-10-24 02:54:21 -07:00
use SymbolSpec::*;
let ast::QualifiedName { id, components, .. } = qualified_name;
2021-10-24 02:54:21 -07:00
let symbol = match self.symbol_table.lookup_symbol(&qualified_name.id) {
Some(s) => s,
None => return Expression::ReductionError(format!("No symbol found for name: {:?}", qualified_name))
};
let Symbol { def_id, spec, .. } = symbol;
match spec {
Func(_) => Expression::Lookup { id: def_id.clone(), kind: Lookup::Function },
GlobalBinding => Expression::Lookup { id: def_id.clone(), kind: Lookup::GlobalVar },
LocalVariable => Expression::Lookup { id: def_id.clone(), kind: Lookup::LocalVar },
2021-10-24 17:57:56 -07:00
FunctionParam(n) => Expression::Lookup { id: def_id.clone(), kind: Lookup::Param(*n) },
2021-10-24 02:54:21 -07:00
DataConstructor { index, arity, .. } => {
Expression::Unimplemented
},
RecordConstructor { .. } => {
Expression::ReductionError(format!("The symbol for value {:?} is unexpectdly a RecordConstructor", qualified_name))
},
}
}
}