Skip to content

Commit

Permalink
Massive feature drop
Browse files Browse the repository at this point in the history
- pattern matching seems to be correct
- dynamic dispatch works with the to_string example
- template strings as a last-minute addition
- interpreter revamp, virtual stack for abort safety
  • Loading branch information
lbfalvy committed Jan 29, 2024
1 parent a888722 commit c279301
Show file tree
Hide file tree
Showing 71 changed files with 947 additions and 932 deletions.
13 changes: 7 additions & 6 deletions examples/hello-world/main.orc
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import std::exit_status
import std::conv
import std::number
import std::tuple
import std::list

const main2 := (
println "Hello, world!"
exit_status::success
)

const main := conv::to_string t[1, 2, 3]
const main := match t["set", "foo", 1] {
t[= "set", key, val] =>
$"Setting ${ key ++ $"${1 + 1}" } to ${val}"
}
6 changes: 4 additions & 2 deletions orchid.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
"editor.lineNumbers": "off",
"editor.glyphMargin": false,
"editor.rulers": [],
"editor.guides.indentation": false,
"editor.guides.indentation": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
},
"[rust]": {
"editor.rulers": [80],
"editor.rulers": [
100
],
},
"rust-analyzer.showUnlinkedFileNotification": false,
"rust-analyzer.checkOnSave": true,
Expand Down
2 changes: 1 addition & 1 deletion rustfmt.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version = "Two"

# space
tab_spaces = 2
max_width = 80
max_width = 100
error_on_line_overflow = true
format_macro_matchers = true
newline_style = "Unix"
Expand Down
1 change: 1 addition & 0 deletions src/bin/orcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ enum Command {
},
#[command(arg_required_else_help = true)]
MacroDebug {
#[arg(long, short)]
symbol: String,
},
ListMacros,
Expand Down
40 changes: 19 additions & 21 deletions src/facade/merge_trees.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
use std::sync::Arc;

use hashbrown::HashMap;
use never::Never;
use substack::Substack;

use super::system::System;
use crate::error::ProjectResult;
use crate::intermediate::ast_to_ir::ast_to_ir;
use crate::intermediate::ir_to_nort::ir_to_nort;
use crate::interpreter::nort;
use crate::location::{CodeGenInfo, CodeLocation};
use crate::name::{Sym, VPath};
use crate::name::Sym;
use crate::pipeline::project::ConstReport;
use crate::tree::{ModMember, ModMemberRef, TreeTransforms};
use crate::tree::{ModMemberRef, TreeTransforms};
use crate::utils::unwrap_or::unwrap_or;

/// Equivalent of [crate::pipeline::project::ConstReport] for the interpreter's
/// representation, [crate::interpreter::nort].
Expand All @@ -33,28 +32,27 @@ pub fn merge_trees<'a: 'b, 'b>(
) -> ProjectResult<impl IntoIterator<Item = (Sym, NortConst)> + 'static> {
let mut out = HashMap::new();
for (name, rep) in source {
let ir = ast_to_ir(rep.value, name.clone())?;
// if name == Sym::literal("tree::main::main") {
// panic!("{ir:?}");
// }
out.insert(name.clone(), NortConst {
value: ir_to_nort(&ast_to_ir(rep.value, name)?),
value: ir_to_nort(&ir),
location: CodeLocation::Source(rep.range),
comments: rep.comments,
});
}
for sys in systems {
let const_module = sys.constants.unwrap_mod_ref();
const_module.search_all((), |path, node, ()| {
let m = if let ModMemberRef::Mod(m) = node { m } else { return };
for (key, ent) in &m.entries {
if let ModMember::Item(c) = &ent.member {
let path = VPath::new(path.unreverse()).as_prefix_of(key.clone());
let location = CodeLocation::Gen(CodeGenInfo::details(
"constant from",
format!("system.name={}", sys.name),
));
let value = c.gen_nort(location.clone());
let crep = NortConst { value, comments: vec![], location };
out.insert(path.to_sym(), crep);
}
}
for system in systems {
let const_module = system.constants.unwrap_mod_ref();
const_module.search_all((), |stack, node, ()| {
let c = unwrap_or!(node => ModMemberRef::Item; return);
let location = CodeLocation::Gen(CodeGenInfo::details(
"constant from",
format!("system.name={}", system.name),
));
let value = c.clone().gen_nort(stack.clone(), location.clone());
let crep = NortConst { value, comments: vec![], location };
out.insert(Sym::new(stack.unreverse()).expect("root item is forbidden"), crep);
});
}
Ok(out)
Expand Down
5 changes: 2 additions & 3 deletions src/facade/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::interpreter::handler::{run_handler, HandlerTable};
use crate::interpreter::nort::{Clause, Expr};
use crate::location::CodeLocation;
use crate::name::Sym;
use crate::utils::boxed_iter::BoxedIter;

/// This struct ties the state of systems to loaded code, and allows to call
/// Orchid-defined functions
Expand Down Expand Up @@ -37,7 +36,7 @@ impl<'a> Process<'a> {
prompt: Expr,
gas: Option<usize>,
) -> Result<Halt, RunError> {
let ctx = RunContext { gas, symbols: &self.symbols };
let ctx = RunContext { gas, symbols: &self.symbols, stack_size: 1000 };
run_handler(prompt, &mut self.handlers, ctx)
}

Expand All @@ -48,7 +47,7 @@ impl<'a> Process<'a> {
let mut errors = Vec::new();
let sym = self.symbols.get(&key).expect("symbol must exist");
sym.search_all(&mut |s: &Expr| {
if let Clause::Constant(sym) = &*s.clause.cls() {
if let Clause::Constant(sym) = &*s.cls() {
if !self.symbols.contains_key(sym) {
errors.push((sym.clone(), s.location()))
}
Expand Down
53 changes: 32 additions & 21 deletions src/foreign/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,27 @@ use std::sync::{Arc, Mutex};
use never::Never;

use super::error::{ExternError, ExternResult};
use crate::interpreter::apply::CallData;
use crate::interpreter::context::RunContext;
use crate::interpreter::error::RunError;
use crate::interpreter::nort;
use crate::interpreter::run::RunData;
use crate::location::{CodeLocation, SourceRange};
use crate::name::NameLike;
use crate::parse::parsed;
use crate::utils::ddispatch::{request, Request, Responder};

/// Information returned by [Atomic::run]. This mirrors
/// [crate::interpreter::Return] but with a clause instead of an Expr.
pub struct AtomicReturn {
/// The next form of the expression
pub clause: nort::Clause,
/// Remaining gas
pub gas: Option<usize>,
/// Whether further normalization is possible by repeated calls to
/// [Atomic::run]
pub inert: bool,
/// Information returned by [Atomic::run].
pub enum AtomicReturn {
/// No work was done. If the atom takes an argument, it can be provided now
Inert(nort::Clause),
/// Work was done, returns new clause and consumed gas. 1 gas is already
/// consumed by the virtual call, so nonzero values indicate expensive
/// operations.
Change(usize, nort::Clause),
}
impl AtomicReturn {
/// Report indicating that the value is inert
pub fn inert<T: Atomic, E>(this: T, ctx: RunContext) -> Result<Self, E> {
Ok(Self { clause: this.atom_cls(), gas: ctx.gas, inert: true })
}
/// Report indicating that the value has been processed
pub fn run<E>(clause: nort::Clause, run: RunData) -> Result<Self, E> {
Ok(Self { clause, gas: run.ctx.gas, inert: false })
pub fn inert<T: Atomic, E>(this: T) -> Result<Self, E> {
Ok(Self::Inert(this.atom_cls()))
}
}

Expand All @@ -51,6 +43,25 @@ impl Display for NotAFunction {
}
}

/// Information about a function call presented to an external function
pub struct CallData<'a> {
/// Location of the function expression
pub location: CodeLocation,
/// The argument the function was called on. Functions are curried
pub arg: nort::Expr,
/// Information relating to this interpreter run
pub ctx: RunContext<'a>,
}

/// Information about a normalization run presented to an atom
#[derive(Clone)]
pub struct RunData<'a> {
/// Location of the atom
pub location: CodeLocation,
/// Information about the execution
pub ctx: RunContext<'a>,
}

/// Functionality the interpreter needs to handle a value
///
/// # Lifecycle methods
Expand Down Expand Up @@ -91,7 +102,7 @@ where Self: 'static

/// Returns a reference to a possible expression held inside the atom which
/// can be reduced. For an overview of the lifecycle see [Atomic]
fn redirect(&mut self) -> Option<&mut nort::ClauseInst>;
fn redirect(&mut self) -> Option<&mut nort::Expr>;

/// Attempt to normalize this value. If it wraps a value, this should report
/// inert. If it wraps a computation, it should execute one logical step of
Expand Down Expand Up @@ -172,7 +183,7 @@ impl AtomGenerator {
}
impl Debug for AtomGenerator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AtomGenerator").finish_non_exhaustive()
write!(f, "{:?}", self.run())
}
}

Expand Down Expand Up @@ -239,7 +250,7 @@ impl Responder for Never {
impl Atomic for Never {
fn as_any(self: Box<Self>) -> Box<dyn Any> { match *self {} }
fn as_any_ref(&self) -> &dyn Any { match *self {} }
fn redirect(&mut self) -> Option<&mut nort::ClauseInst> { match *self {} }
fn redirect(&mut self) -> Option<&mut nort::Expr> { match *self {} }
fn run(self: Box<Self>, _: RunData) -> AtomicResult { match *self {} }
fn apply_ref(&self, _: CallData) -> ExternResult<nort::Clause> {
match *self {}
Expand Down
14 changes: 7 additions & 7 deletions src/foreign/cps_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use std::fmt::Debug;

use trait_set::trait_set;

use super::atom::{Atomic, AtomicResult, AtomicReturn, NotAFunction};
use super::atom::{
Atomic, AtomicResult, AtomicReturn, CallData, NotAFunction, RunData,
};
use super::error::{ExternError, ExternResult};
use crate::interpreter::apply::CallData;
use crate::interpreter::nort::{Clause, ClauseInst, Expr};
use crate::interpreter::run::RunData;
use crate::interpreter::nort::{Clause, Expr};
use crate::location::CodeLocation;
use crate::utils::ddispatch::{Request, Responder};
use crate::utils::pure_seq::pushed_ref;
Expand Down Expand Up @@ -78,9 +78,9 @@ impl<T: CPSPayload> Atomic for CPSBox<T> {
fn as_any(self: Box<Self>) -> Box<dyn std::any::Any> { self }
fn as_any_ref(&self) -> &dyn std::any::Any { self }
fn parser_eq(&self, _: &dyn std::any::Any) -> bool { false }
fn redirect(&mut self) -> Option<&mut ClauseInst> { None }
fn run(self: Box<Self>, run: RunData) -> AtomicResult {
AtomicReturn::inert(*self, run.ctx)
fn redirect(&mut self) -> Option<&mut Expr> { None }
fn run(self: Box<Self>, _: RunData) -> AtomicResult {
AtomicReturn::inert(*self)
}
fn apply(mut self: Box<Self>, call: CallData) -> ExternResult<Clause> {
self.assert_applicable(&call.location)?;
Expand Down
9 changes: 6 additions & 3 deletions src/foreign/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::location::CodeLocation;
pub trait ExternError: Display + Send + Sync + DynClone {
/// Convert into trait object
#[must_use]
fn rc(self) -> Arc<dyn ExternError>
fn rc(self) -> ExternErrorObj
where Self: 'static + Sized {
Arc::new(self)
}
Expand All @@ -25,7 +25,10 @@ impl Debug for dyn ExternError {
impl Error for dyn ExternError {}

/// An error produced by Rust code called form Orchid. The error is type-erased.
pub type ExternResult<T> = Result<T, Arc<dyn ExternError>>;
pub type ExternErrorObj = Arc<dyn ExternError>;

/// A result produced by Rust code called from Orchid.
pub type ExternResult<T> = Result<T, ExternErrorObj>;

/// Some expectation (usually about the argument types of a function) did not
/// hold.
Expand All @@ -52,7 +55,7 @@ impl AssertionError {
location: CodeLocation,
message: &'static str,
details: String,
) -> Arc<dyn ExternError> {
) -> ExternErrorObj {
Self { location, message, details }.rc()
}
}
Expand Down
Loading

0 comments on commit c279301

Please sign in to comment.