2022-08-01 05:32:47 +00:00
|
|
|
use ordered_float::OrderedFloat;
|
|
|
|
use salsa::debug::DebugWithDb;
|
|
|
|
|
2022-08-03 04:41:36 +00:00
|
|
|
// ANCHOR: input
|
|
|
|
#[salsa::input]
|
|
|
|
pub struct SourceProgram {
|
|
|
|
#[return_ref]
|
|
|
|
text: String,
|
|
|
|
}
|
|
|
|
// ANCHOR_END: input
|
|
|
|
|
2022-08-01 05:32:47 +00:00
|
|
|
// ANCHOR: interned_ids
|
|
|
|
#[salsa::interned]
|
|
|
|
pub struct VariableId {
|
|
|
|
#[return_ref]
|
|
|
|
pub text: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[salsa::interned]
|
|
|
|
pub struct FunctionId {
|
|
|
|
#[return_ref]
|
|
|
|
pub text: String,
|
|
|
|
}
|
|
|
|
// ANCHOR_END: interned_ids
|
|
|
|
|
|
|
|
// ANCHOR: statements_and_expressions
|
|
|
|
#[salsa::interned]
|
2022-08-03 07:43:39 +00:00
|
|
|
pub struct Statement {
|
|
|
|
data: StatementData,
|
|
|
|
}
|
|
|
|
|
2022-08-01 05:32:47 +00:00
|
|
|
#[derive(Eq, PartialEq, Clone, Hash)]
|
2022-08-03 07:43:39 +00:00
|
|
|
pub enum StatementData {
|
2022-08-01 05:32:47 +00:00
|
|
|
/// Defines `fn <name>(<args>) = <body>`
|
|
|
|
Function(Function),
|
|
|
|
/// Defines `print <expr>`
|
|
|
|
Print(Expression),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[salsa::interned]
|
2022-08-03 07:43:39 +00:00
|
|
|
pub struct Expression {
|
|
|
|
#[return_ref]
|
|
|
|
data: ExpressionData,
|
|
|
|
}
|
|
|
|
|
2022-08-01 05:32:47 +00:00
|
|
|
#[derive(Eq, PartialEq, Clone, Hash)]
|
2022-08-03 07:43:39 +00:00
|
|
|
pub enum ExpressionData {
|
2022-08-01 05:32:47 +00:00
|
|
|
Op(Expression, Op, Expression),
|
|
|
|
Number(OrderedFloat<f64>),
|
|
|
|
Variable(VariableId),
|
|
|
|
Call(FunctionId, Vec<Expression>),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Eq, PartialEq, Copy, Clone, Hash, Debug)]
|
|
|
|
pub enum Op {
|
|
|
|
Add,
|
|
|
|
Subtract,
|
|
|
|
Multiply,
|
|
|
|
Divide,
|
|
|
|
}
|
|
|
|
// ANCHOR_END: statements_and_expressions
|
|
|
|
|
|
|
|
impl DebugWithDb<dyn crate::Db + '_> for Function {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result {
|
|
|
|
f.debug_struct("Function")
|
|
|
|
.field("name", &self.name(db).debug(db))
|
|
|
|
.field("args", &self.args(db).debug(db))
|
|
|
|
.field("body", &self.body(db).debug(db))
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DebugWithDb<dyn crate::Db + '_> for Statement {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result {
|
|
|
|
match self.data(db) {
|
2022-08-03 07:43:39 +00:00
|
|
|
StatementData::Function(a) => DebugWithDb::fmt(&a, f, db),
|
|
|
|
StatementData::Print(a) => DebugWithDb::fmt(&a, f, db),
|
2022-08-01 05:32:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ANCHOR: expression_debug_impl
|
|
|
|
impl DebugWithDb<dyn crate::Db + '_> for Expression {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result {
|
|
|
|
match self.data(db) {
|
|
|
|
ExpressionData::Op(a, b, c) => f
|
|
|
|
.debug_tuple("ExpressionData::Op")
|
|
|
|
.field(&a.debug(db)) // use `a.debug(db)` for interned things
|
|
|
|
.field(&b.debug(db))
|
|
|
|
.field(&c.debug(db))
|
|
|
|
.finish(),
|
|
|
|
ExpressionData::Number(a) => {
|
|
|
|
f.debug_tuple("Number")
|
|
|
|
.field(a) // use just `a` otherwise
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
ExpressionData::Variable(a) => f.debug_tuple("Variable").field(&a.debug(db)).finish(),
|
|
|
|
ExpressionData::Call(a, b) => f
|
|
|
|
.debug_tuple("Call")
|
|
|
|
.field(&a.debug(db))
|
|
|
|
.field(&b.debug(db))
|
|
|
|
.finish(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ANCHOR_END: expression_debug_impl
|
|
|
|
|
|
|
|
impl DebugWithDb<dyn crate::Db + '_> for FunctionId {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result {
|
|
|
|
write!(f, "{:?}", self.text(db))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DebugWithDb<dyn crate::Db + '_> for VariableId {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result {
|
|
|
|
write!(f, "{:?}", self.text(db))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ANCHOR: op_debug_impl
|
|
|
|
impl DebugWithDb<dyn crate::Db + '_> for Op {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, _db: &dyn crate::Db) -> std::fmt::Result {
|
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ANCHOR: op_debug_impl
|
|
|
|
|
|
|
|
impl DebugWithDb<dyn crate::Db + '_> for Diagnostic {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, _db: &dyn crate::Db) -> std::fmt::Result {
|
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ANCHOR: functions
|
2022-08-03 13:09:22 +00:00
|
|
|
#[salsa::tracked]
|
2022-08-01 05:32:47 +00:00
|
|
|
pub struct Function {
|
|
|
|
#[id]
|
|
|
|
name: FunctionId,
|
|
|
|
args: Vec<VariableId>,
|
|
|
|
body: Expression,
|
|
|
|
}
|
|
|
|
// ANCHOR_END: functions
|
|
|
|
|
|
|
|
// ANCHOR: diagnostic
|
|
|
|
#[salsa::accumulator]
|
|
|
|
pub struct Diagnostics(Diagnostic);
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct Diagnostic {
|
|
|
|
pub position: usize,
|
|
|
|
pub message: String,
|
|
|
|
}
|
|
|
|
// ANCHOR_END: diagnostic
|