Skip to content

Commit

Permalink
fire: Add handling of builtin arithmetic operations
Browse files Browse the repository at this point in the history
  • Loading branch information
CohenArthur committed Oct 22, 2023
1 parent 6917994 commit 9fc5b0a
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 42 deletions.
1 change: 1 addition & 0 deletions fire/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ name_resolve = { path = "../name_resolve" }
typecheck = { path = "../typecheck" }
xparser = { path = "../xparser" }
location = { path = "../location" }
builtins = { path = "../builtins" }
67 changes: 25 additions & 42 deletions fire/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use instance::Instance;
use fir::{Fir, Kind, Node, OriginIdx, RefIdx};
use flatten::FlattenData;

mod outside;

// Emit a fatal error from the [`Fire`].
// macro_rules! fire_fatal {
// ($fmt:literal $($args:tt),*) => {
Expand Down Expand Up @@ -57,7 +59,7 @@ impl Interpret for Fir<FlattenData<'_>> {
}

/// It's called [`GarbajKollector`] because this way you have "jk" in the middle of the word :)
struct GarbaJKollector(HashMap<OriginIdx, Instance>);
pub struct GarbaJKollector(HashMap<OriginIdx, Instance>);

// FIXME: Add documentation for all methods
impl GarbaJKollector {
Expand Down Expand Up @@ -118,38 +120,6 @@ impl<'ast, 'fir> Fire<'ast, 'fir> {
&self.fir.nodes[&resolved]
}

// TODO: Move outside of the impl block?
fn perform_extern_call(
&self,
node: &Node<FlattenData<'_>>,
args: &[RefIdx],
) -> Option<Instance> {
let ast = node.data.ast.node();
let name = match &ast.node {
ast::Node::Function {
decl: ast::Declaration { name, .. },
..
} => name,
other => {
dbg!(other);
unreachable!()
}
};

if name.access() == "println" {
args.iter().for_each(|arg| {
let value = self.gc.lookup(&arg.expect_resolved()).unwrap();
if let Instance::String(s) = value {
println!("{s}");
} else {
unreachable!("typecheck didn't catch this error. this is an interpreter bug.");
}
})
}

None
}

#[must_use]
fn fire_block(
&mut self,
Expand Down Expand Up @@ -215,7 +185,7 @@ impl<'ast, 'fir> Fire<'ast, 'fir> {
// FIXME: We need to add bindings here between the function's variables and the arguments given to the call
match block {
None => {
let result = self.perform_extern_call(def, args);
let result = outside::perform_call(&self.gc, def, args);
if let Some(instance) = result {
self.gc.allocate(node.origin, instance);
}
Expand Down Expand Up @@ -413,20 +383,25 @@ impl<'ast, 'fir> Fire<'ast, 'fir> {
#[cfg(test)]
mod tests {
use super::*;
use builtins::AppendAstBuiltins;
use flatten::FlattenAst;
use name_resolve::NameResolve;
use typecheck::TypeCheck;

macro_rules! ast {
($($toks:tt)*) => {
xparser::ast!(
type char;
type bool;
type int;
type float;
type string;
$($toks)*
)
{
let ast = xparser::ast!(
type char;
type bool;
type int;
type float;
type string;
$($toks)*
);

ast.append_builtins().unwrap()
}
}
}

Expand Down Expand Up @@ -597,4 +572,12 @@ mod tests {
let result = fir!(ast).interpret();
assert_eq!(result, Some(Instance::from("one")));
}

#[test]
fn arithmetic() {
let ast = ast! { 14 * 2 };

let result = fir!(ast).interpret();
assert_eq!(result, Some(Instance::from(28)));
}
}
104 changes: 104 additions & 0 deletions fire/src/outside.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//! This module takes care of performing calls to extern functions. Extern functions will
//! either be builtins, or C functions defined in a dynamic library loaded with the `link_with`
//! builtin.
use fir::{Node, RefIdx};
use flatten::FlattenData;

use crate::instance::Instance;
use crate::GarbaJKollector;

// TODO: Factor this with `ast_builtins`?
static ARITHMETIC_BUILTINS: &[&'static str] = &["+", "-", "*", "/"];

Check failure on line 12 in fire/src/outside.rs

View workflow job for this annotation

GitHub Actions / clippy

statics have by default a `'static` lifetime

error: statics have by default a `'static` lifetime --> fire/src/outside.rs:12:32 | 12 | static ARITHMETIC_BUILTINS: &[&'static str] = &["+", "-", "*", "/"]; | -^^^^^^^---- help: consider removing `'static`: `&str` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings`

enum Arithmetic {
Add,
Sub,
Mul,
Div,
}

impl From<&str> for Arithmetic {
fn from(s: &str) -> Self {
match s {
"+" => Arithmetic::Add,
"-" => Arithmetic::Sub,
"*" => Arithmetic::Mul,
"/" => Arithmetic::Div,
_ => unreachable!("this is an interpreter error."),
}
}
}

pub fn perform_call(
// FIXME: This should probably take a context, correct? &self?
gc: &GarbaJKollector,
node: &Node<FlattenData<'_>>,
args: &[RefIdx],
) -> Option<Instance> {
let ast = node.data.ast.node();
let name = match &ast.node {
ast::Node::Function {
decl: ast::Declaration { name, .. },
..
} => name,
other => {
dbg!(other);
unreachable!()
}
};

if ARITHMETIC_BUILTINS.contains(&name.access()) {
return Some(arithmetic_builtin_call(
gc,
args,
Arithmetic::from(name.access()),
));
}

if name.access() == "println" {
args.iter().for_each(|arg| {
let value = gc.lookup(&arg.expect_resolved()).unwrap();
if let Instance::String(s) = value {
println!("{s}");
} else {
unreachable!("typecheck didn't catch this error. this is an interpreter bug.");
}
})
}

None
}

fn int_op(lhs: &i64, rhs: &i64, op: Arithmetic) -> Instance {
let res = match op {
Arithmetic::Add => lhs + rhs,
Arithmetic::Sub => lhs - rhs,
Arithmetic::Mul => lhs * rhs,
Arithmetic::Div => lhs / rhs,
};

Instance::Int(res)
}

fn float_op(lhs: &f64, rhs: &f64, op: Arithmetic) -> Instance {
let res = match op {
Arithmetic::Add => lhs + rhs,
Arithmetic::Sub => lhs - rhs,
Arithmetic::Mul => lhs * rhs,
Arithmetic::Div => lhs / rhs,
};

Instance::Float(res)
}

fn arithmetic_builtin_call(gc: &GarbaJKollector, args: &[RefIdx], op: Arithmetic) -> Instance {
let lhs = gc.lookup(&args[0].expect_resolved()).unwrap();
let rhs = gc.lookup(&args[1].expect_resolved()).unwrap();

match (lhs, rhs) {
(Instance::Int(l), Instance::Int(r)) => int_op(l, r, op),
(Instance::Float(l), Instance::Float(r)) => float_op(l, r, op),
_ => unreachable!("fuck me"),
}
}

0 comments on commit 9fc5b0a

Please sign in to comment.