Skip to content

Commit

Permalink
add (optional) ability to create sequence to map array/list from fron…
Browse files Browse the repository at this point in the history
…tends

at the exec level, introduce a new explicit CallNif that takes the NifId in parameter
  • Loading branch information
vincenthz committed Jan 19, 2024
1 parent 70faa31 commit 70581d5
Show file tree
Hide file tree
Showing 12 changed files with 105 additions and 22 deletions.
28 changes: 23 additions & 5 deletions werbolg-compile/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,23 @@ fn generate_expression_code<'a, L: Clone + Eq + core::hash::Hash>(
}
Ok(false)
}
ir::Expr::List(_span, _l) => {
todo!("list ?")
ir::Expr::Sequence(span, l) => {
let call_arity = l
.len()
.try_into()
.map_err(|sz| CompilationError::CallTooManyArguments(span.clone(), sz))?;
for e in l {
let _: bool = generate_expression_code(state, local, FunPos::NotRoot, e)?;
}
match &state.params.sequence_constructor {
None => return Err(CompilationError::SequenceNotSupported(span)),
Some(nifid) => {
state
.write_code()
.push(Instruction::CallNif(*nifid, call_arity));
Ok(true)
}
}
}
ir::Expr::Let(binder, body, in_expr) => {
let x = body.clone();
Expand Down Expand Up @@ -280,22 +295,25 @@ fn generate_expression_code<'a, L: Clone + Eq + core::hash::Hash>(

Ok(false)
}
ir::Expr::Call(_span, args) => {
ir::Expr::Call(span, args) => {
assert!(args.len() > 0);
let len = args.len() - 1;
for arg in args {
let _: bool = generate_expression_code(state, local, FunPos::NotRoot, arg)?;
()
}
let call_arity = len
.try_into()
.map_err(|sz| CompilationError::CallTooManyArguments(span, sz))?;
if funpos == FunPos::Root {
state
.write_code()
.push(Instruction::Call(TailCall::Yes, CallArity(len as u8)));
.push(Instruction::Call(TailCall::Yes, call_arity));
Ok(true)
} else {
state
.write_code()
.push(Instruction::Call(TailCall::No, CallArity(len as u8)));
.push(Instruction::Call(TailCall::No, call_arity));
Ok(false)
}
}
Expand Down
6 changes: 6 additions & 0 deletions werbolg-compile/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ pub enum CompilationError {
FunctionParamsMoreThanLimit(Span, usize),
/// Core's Literal is not supported by this compiler
LiteralNotSupported(Span, Literal),
/// Core's Sequence is not supported by this compiler
SequenceNotSupported(Span),
/// The constructor specified is a not a structure, but trying to access inner field
ConstructorNotStructure(Span, Path),
/// The structure specified doesn't have a field of the right name
StructureFieldNotExistant(Span, Path, Ident),
/// Namespace Error
NamespaceError(NamespaceError),
/// Too Many argument to call
CallTooManyArguments(Span, usize),
/// A recursive compilation with some context added
Context(String, Box<CompilationError>),
}
Expand All @@ -35,9 +39,11 @@ impl CompilationError {
CompilationError::MissingConstructor(span, _) => span.clone(),
CompilationError::FunctionParamsMoreThanLimit(span, _) => span.clone(),
CompilationError::LiteralNotSupported(span, _) => span.clone(),
CompilationError::SequenceNotSupported(span) => span.clone(),
CompilationError::ConstructorNotStructure(span, _) => span.clone(),
CompilationError::StructureFieldNotExistant(span, _, _) => span.clone(),
CompilationError::NamespaceError(_) => todo!(),
CompilationError::CallTooManyArguments(span, _) => span.clone(),
CompilationError::Context(_, e) => e.span(),
}
}
Expand Down
21 changes: 21 additions & 0 deletions werbolg-compile/src/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ pub enum Instruction {
///
/// expecting N+1 value on the value stack
Call(TailCall, CallArity),
/// Call the Nif function on the stack with the N value in arguments.
///
/// expecting N value on the value stack, as the NifId is embedded in the instruction
CallNif(NifId, CallArity),
/// Jump by N instructions
Jump(InstructionDiff),
/// Jump by N instructions if stack\[top\] is true
Expand Down Expand Up @@ -64,3 +68,20 @@ pub struct StructFieldIndex(pub u8);
/// This is limited (arbitrarily) to a maximum of 255
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CallArity(pub u8);

impl TryFrom<usize> for CallArity {
type Error = usize;
fn try_from(value: usize) -> Result<Self, Self::Error> {
value.try_into().map(|v| CallArity(v)).map_err(|_| value)
}
}

impl TryFrom<u32> for CallArity {
type Error = usize;
fn try_from(value: u32) -> Result<Self, Self::Error> {
value
.try_into()
.map(|v| CallArity(v))
.map_err(|_| value as usize)
}
}
7 changes: 5 additions & 2 deletions werbolg-compile/src/params.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use super::CompilationError;
use werbolg_core::Literal;
use werbolg_core::Span;
use werbolg_core::{Literal, NifId, Span};

/// User driven compilation parameters
#[derive(Clone)]
pub struct CompilationParams<L: Clone + Eq + core::hash::Hash> {
/// Map a werbolg-literal into a L type that will be used during execution
pub literal_mapper: fn(Span, Literal) -> Result<L, CompilationError>,

/// Constructor for a possible sequence of expression (list or array), that
/// take usize argument from the stack
pub sequence_constructor: Option<NifId>,
}
4 changes: 2 additions & 2 deletions werbolg-core/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ pub enum Expr {
/// either by disambiguating at the frontend level by adding explicit struct name
/// or by other methods
Field(Box<Expr>, Spanned<Path>, Spanned<Ident>),
/// A List expression
List(Span, Vec<Expr>),
/// A Sequence of expressions
Sequence(Span, Vec<Expr>),
/// A Let binding of the form `let $binder = $expr in $expr`
Let(Binder, Box<Expr>, Box<Expr>),
/// An anonymous function definition expression, e.g. `|a| ...` or `\x -> ...`
Expand Down
5 changes: 4 additions & 1 deletion werbolg-example1/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,10 @@ fn main() -> Result<(), ()> {
add_pure_nif!(env, "table_new", nif_hashtable);
add_pure_nif!(env, "table_get", nif_hashtable_get);

let compilation_params = werbolg_compile::CompilationParams { literal_mapper };
let compilation_params = werbolg_compile::CompilationParams {
literal_mapper,
sequence_constructor: None,
};
let exec_module =
compile(&compilation_params, modules, &mut env).expect("no compilation error");

Expand Down
31 changes: 23 additions & 8 deletions werbolg-exec/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use super::allocator::WAllocator;
use super::{ExecutionError, ExecutionMachine};
use werbolg_compile::{CallArity, Instruction, InstructionAddress, LocalStackSize, TailCall};
use werbolg_core as ir;
use werbolg_core::ValueFun;
use werbolg_core::{NifId, ValueFun};

/// Native Implemented Function
pub struct NIF<'m, 'e, A, L, T, V> {
Expand Down Expand Up @@ -224,6 +224,12 @@ pub fn step<'m, 'e, A: WAllocator<Value = V>, L, T, V: Valuable>(
let _ = em.stack.pop_value();
em.ip_next();
}
Instruction::CallNif(nif, arity) => {
let nif_value = process_nif_call(em, *nif, *arity)?;
em.stack.pop_call_nofun(*arity);
em.stack.push_value(nif_value);
em.ip_next()
}
Instruction::Call(tc, arity) => {
let val = process_call(em, *arity)?;
match val {
Expand Down Expand Up @@ -323,13 +329,7 @@ fn process_call<'m, 'e, A: WAllocator, L, T, V: Valuable>(

match fun {
ValueFun::Native(nifid) => {
let res = match &em.environ.nifs[nifid].call {
NIFCall::Pure(nif) => {
let (_first, args) = em.stack.get_call_and_args(arity);
nif(&em.allocator, args)?
}
NIFCall::Raw(nif) => nif(em)?,
};
let res = process_nif_call(em, nifid, arity)?;
Ok(CallResult::Value(res))
}
ValueFun::Fun(funid) => {
Expand All @@ -345,3 +345,18 @@ fn process_call<'m, 'e, A: WAllocator, L, T, V: Valuable>(
}
}
}

fn process_nif_call<'m, 'e, A: WAllocator, L, T, V: Valuable>(
em: &mut ExecutionMachine<'m, 'e, A, L, T, V>,
nifid: NifId,
arity: CallArity,
) -> Result<V, ExecutionError> {
let res = match &em.environ.nifs[nifid].call {
NIFCall::Pure(nif) => {
let args = em.stack.get_call_args(arity);
nif(&em.allocator, args)?
}
NIFCall::Raw(nif) => nif(em)?,
};
Ok(res)
}
13 changes: 13 additions & 0 deletions werbolg-exec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ impl<V: Valuable> ValueStack<V> {
self.values.extend_from_slice(args);
}

/// Pop a call from the stack
pub fn pop_call_nofun(&mut self, arity: CallArity) {
for _ in 0..(arity.0 as usize) + 1 {
self.values.pop();
}
}

/// Pop a call from the stack
pub fn pop_call(&mut self, arity: CallArity) {
for _ in 0..(arity.0 as usize) + 1 {
Expand Down Expand Up @@ -187,6 +194,12 @@ impl<V: Valuable> ValueStack<V> {
)
}

/// Get the associated arguments with a call
pub fn get_call_args(&self, arity: CallArity) -> &[V] {
let top = self.values.len();
&self.values[top - (arity.0 as usize)..top]
}

/// Iterate over all values in the stack, starting from the bottom, towards the end
pub fn iter_pos(&self) -> impl Iterator<Item = (StackPointer, &V)> {
self.values
Expand Down
4 changes: 2 additions & 2 deletions werbolg-lang-lispy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,12 @@ fn exprs(span: Span, exprs: Vec<Spanned<Ast>>) -> Result<ir::Expr, ParseError> {
.collect::<Result<Vec<_>, _>>()?;

if build_list {
Ok(ir::Expr::List(span, params))
Ok(ir::Expr::Sequence(span, params))
} else {
let params = params
.into_iter()
.filter(|e| match e {
ir::Expr::List(_, e) if e.is_empty() => false,
ir::Expr::Sequence(_, e) if e.is_empty() => false,
_ => true,
})
.collect();
Expand Down
2 changes: 1 addition & 1 deletion werbolg-lang-rusty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn rewrite_expr(span_expr: &(parse::Expr, parse::Span)) -> ir::Expr {
match &span_expr.0 {
parse::Expr::Error => todo!(),
parse::Expr::Literal(lit) => ir::Expr::Literal(span_expr.1.clone(), lit.clone()),
parse::Expr::List(list) => ir::Expr::List(
parse::Expr::List(list) => ir::Expr::Sequence(
span_expr.1.clone(),
list.iter().map(|se| rewrite_expr(se)).collect::<Vec<_>>(),
),
Expand Down
1 change: 1 addition & 0 deletions werbolg-tales/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pub fn run_compile<'m, 'e, A>(

let compilation_params = werbolg_compile::CompilationParams {
literal_mapper: environ::literal_mapper,
sequence_constructor: None,
};

let exec_module = match compile(&compilation_params, modules, env) {
Expand Down
5 changes: 4 additions & 1 deletion werbolg-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ pub fn execute(mod1: werbolg_core::Module) -> Result<Value, ExecutionError> {
add_pure_nif!(environ, "bool_eq", nif_bool_eq);
add_pure_nif!(environ, "expect_int", nif_expect_int_eq);
add_pure_nif!(environ, "int_eq", nif_int_eq);
let compilation_params = werbolg_compile::CompilationParams { literal_mapper };
let compilation_params = werbolg_compile::CompilationParams {
literal_mapper,
sequence_constructor: None,
};
let exec_module =
comp(&compilation_params, modules, &mut environ).expect("no compilation error");
let ee = ExecutionEnviron::from_compile_environment(environ.finalize());
Expand Down

0 comments on commit 70581d5

Please sign in to comment.