Skip to content

Commit

Permalink
Populating methods for all primitive types into a new methods table r…
Browse files Browse the repository at this point in the history
…eturned by the prelude
  • Loading branch information
sunjay committed Oct 11, 2020
1 parent 6416e1a commit 78e9e1c
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pub fn compile(
let mut packages = package::Packages::default();

let mut consts = bytecode::Constants::default();
let prelude = prelude::populate(packages.add_package(), &mut consts);
let (prelude, prim_methods) = prelude::populate(packages.add_package(), &mut consts);

let root_module = {
// New scope because we want to drop this lock guard as soon as possible
Expand Down
120 changes: 117 additions & 3 deletions src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
mod prim_methods;

pub use prim_methods::*;

use std::{sync::Arc, time::{SystemTime, UNIX_EPOCH}};

use crate::{
bytecode,
ty::Ty,
gc::Gc,
interpreter::{Interpreter, RuntimeError},
package::{Package, PkgId},
prim::IntoNativeFunc,
prim::{self, IntoNativeFunc},
value::Value,
};

pub fn populate(pkg_id: PkgId, consts: &mut bytecode::Constants) -> Package {
pub fn populate(pkg_id: PkgId, consts: &mut bytecode::Constants) -> (Package, PrimMethods) {
let mut package = Package::new(pkg_id, "prelude");

insert_native_func_into_root_module(&mut package, consts, "clock", clock);

package
let mut prim_methods = PrimMethods::default();
populate_prim_methods(&mut package, consts, &mut prim_methods);

(package, prim_methods)
}

fn insert_native_func_into_root_module<A>(
Expand Down Expand Up @@ -54,3 +62,109 @@ fn clock(_: &mut Interpreter) -> Result<i64, RuntimeError> {

Ok(since_the_epoch)
}

fn populate_prim_methods(
package: &mut Package,
consts: &mut bytecode::Constants,
prim_methods: &mut PrimMethods,
) {
populate_unit_methods(package, consts, &mut prim_methods.unit);
populate_bool_methods(package, consts, &mut prim_methods.bool);
populate_i64_methods(package, consts, &mut prim_methods.i64);
populate_u8_methods(package, consts, &mut prim_methods.u8);
populate_list_methods(package, consts, &mut prim_methods.list);
}

fn populate_unit_methods(
package: &mut Package,
consts: &mut bytecode::Constants,
methods: &mut Methods,
) {
insert_method(package, consts, methods, "==", |_: &mut _, x: (), y: ()| Ok(x == y));
insert_method(package, consts, methods, "!=", |_: &mut _, x: (), y: ()| Ok(x != y));
}

fn populate_bool_methods(
package: &mut Package,
consts: &mut bytecode::Constants,
methods: &mut Methods,
) {
insert_method(package, consts, methods, "not", |_: &mut _, x: bool| Ok(!x));

insert_method(package, consts, methods, "==", |_: &mut _, x: bool, y: bool| Ok(x == y));
insert_method(package, consts, methods, "!=", |_: &mut _, x: bool, y: bool| Ok(x != y));
}

fn populate_i64_methods(
package: &mut Package,
consts: &mut bytecode::Constants,
methods: &mut Methods,
) {
insert_method(package, consts, methods, "neg", |_: &mut _, x: i64| Ok(-x));
// unary `+` has no effect on integers
insert_method(package, consts, methods, "pos", |_: &mut _, x: i64| Ok(x));

insert_method(package, consts, methods, "add", |_: &mut _, x: i64, y: i64| Ok(x + y));
insert_method(package, consts, methods, "sub", |_: &mut _, x: i64, y: i64| Ok(x - y));
insert_method(package, consts, methods, "mul", |_: &mut _, x: i64, y: i64| Ok(x * y));
insert_method(package, consts, methods, "div", |_: &mut _, x: i64, y: i64| Ok(x / y));
insert_method(package, consts, methods, "rem", |_: &mut _, x: i64, y: i64| Ok(x % y));

insert_method(package, consts, methods, "==", |_: &mut _, x: i64, y: i64| Ok(x == y));
insert_method(package, consts, methods, "!=", |_: &mut _, x: i64, y: i64| Ok(x != y));
insert_method(package, consts, methods, ">", |_: &mut _, x: i64, y: i64| Ok(x > y));
insert_method(package, consts, methods, ">=", |_: &mut _, x: i64, y: i64| Ok(x >= y));
insert_method(package, consts, methods, "<", |_: &mut _, x: i64, y: i64| Ok(x < y));
insert_method(package, consts, methods, "<=", |_: &mut _, x: i64, y: i64| Ok(x <= y));
}

fn populate_u8_methods(
package: &mut Package,
consts: &mut bytecode::Constants,
methods: &mut Methods,
) {
// unary `+` has no effect on integers
insert_method(package, consts, methods, "pos", |_: &mut _, x: u8| Ok(x));

insert_method(package, consts, methods, "add", |_: &mut _, x: u8, y: u8| Ok(x + y));
insert_method(package, consts, methods, "sub", |_: &mut _, x: u8, y: u8| Ok(x - y));
insert_method(package, consts, methods, "mul", |_: &mut _, x: u8, y: u8| Ok(x * y));
insert_method(package, consts, methods, "div", |_: &mut _, x: u8, y: u8| Ok(x / y));
insert_method(package, consts, methods, "rem", |_: &mut _, x: u8, y: u8| Ok(x % y));

insert_method(package, consts, methods, "==", |_: &mut _, x: u8, y: u8| Ok(x == y));
insert_method(package, consts, methods, "!=", |_: &mut _, x: u8, y: u8| Ok(x != y));
insert_method(package, consts, methods, ">", |_: &mut _, x: u8, y: u8| Ok(x > y));
insert_method(package, consts, methods, ">=", |_: &mut _, x: u8, y: u8| Ok(x >= y));
insert_method(package, consts, methods, "<", |_: &mut _, x: u8, y: u8| Ok(x < y));
insert_method(package, consts, methods, "<=", |_: &mut _, x: u8, y: u8| Ok(x <= y));
}

fn populate_list_methods(
package: &mut Package,
consts: &mut bytecode::Constants,
methods: &mut Methods,
) {
//TODO: Can't add any generic methods because the type system doesn't support polymorphism yet
insert_method(package, consts, methods, "add",
|_: &mut _, x: Gc<prim::Bytes>, y: Gc<prim::Bytes>| Ok(Gc::new(x.add(&y))));

insert_method(package, consts, methods, "==", |_: &mut _, x: Gc<prim::Bytes>, y: Gc<prim::Bytes>| Ok(x == y));
insert_method(package, consts, methods, "!=", |_: &mut _, x: Gc<prim::Bytes>, y: Gc<prim::Bytes>| Ok(x != y));
}

fn insert_method<A>(
package: &mut Package,
consts: &mut bytecode::Constants,
methods: &mut Methods,
name: impl Into<Arc<str>>,
f: impl IntoNativeFunc<A>,
) {
let name = name.into();

let func = f.into_native_func(&name);
let ty = Ty::Func(Box::new(func.ty.clone()));
let const_id = consts.push(func.into());
let def_id = package.insert(name.clone(), ty, const_id);
methods.insert(name, def_id);
}
29 changes: 29 additions & 0 deletions src/prelude/prim_methods.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::{collections::HashMap, sync::Arc};

use crate::nir;

#[derive(Debug, Default)]
pub struct PrimMethods {
pub unit: Methods,
pub bool: Methods,
pub i64: Methods,
pub u8: Methods,
pub list: Methods,
}

#[derive(Debug, Default)]
pub struct Methods {
methods: HashMap<Arc<str>, nir::DefId>,
}

impl Methods {
pub fn insert(&mut self, name: Arc<str>, id: nir::DefId) {
debug_assert!(!self.methods.contains_key(&name),
"bug: inserted same method twice");
self.methods.insert(name, id);
}

pub fn get(&self, name: &str) -> Option<nir::DefId> {
self.methods.get(name).copied()
}
}
12 changes: 10 additions & 2 deletions src/ty.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::{prim, gc::Gc};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Ty {
/// The `()` type
Expand Down Expand Up @@ -49,9 +51,15 @@ impl PrimTy for u8 {
}
}

impl<T: PrimTy> PrimTy for &[T] {
impl PrimTy for prim::Bytes {
fn ty() -> Ty {
Ty::List(Box::new(Ty::U8))
}
}

impl<T: PrimTy> PrimTy for Gc<T> {
fn ty() -> Ty {
Ty::List(Box::new(T::ty()))
T::ty()
}
}

Expand Down

0 comments on commit 78e9e1c

Please sign in to comment.