Completed docs, added icon

This commit is contained in:
2023-05-28 17:24:56 +01:00
parent 6b71164aca
commit 6f5a9d05dd
28 changed files with 295 additions and 5 deletions

View File

@@ -2,7 +2,7 @@
name = "orchidlang" name = "orchidlang"
version = "0.2.1" version = "0.2.1"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "GPL-3.0-or-later"
repository = "https://github.com/lbfalvy/orchid" repository = "https://github.com/lbfalvy/orchid"
description = """ description = """
An embeddable pure functional scripting language An embeddable pure functional scripting language

View File

@@ -19,7 +19,7 @@ Namespaces are inspired by Rust modules and ES6. Every file and directory is imp
The project uses the nighly rust toolchain. Go to one of the folders within `examples` and run The project uses the nighly rust toolchain. Go to one of the folders within `examples` and run
```sh ```sh
cargo run cargo run --release
``` ```
you can try modifying the examples, but error reporting for the time being is pretty terrible. you can try modifying the examples, but error reporting for the time being is pretty terrible.

157
icon.svg Normal file
View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="SVGRoot"
sodipodi:docname="Orchid3.svg"
inkscape:export-filename="bitmap.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview261"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="1"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="px"
showgrid="false"
inkscape:zoom="0.5687738"
inkscape:cx="514.26419"
inkscape:cy="340.20554"
inkscape:window-width="1536"
inkscape:window-height="792"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="true">
<inkscape:grid
type="xygrid"
id="grid384"
originx="0"
originy="0" />
<sodipodi:guide
position="6000,417632"
orientation="0,-1"
id="guide441"
inkscape:locked="false" />
<sodipodi:guide
position="-720,317632"
orientation="1,0"
id="guide443"
inkscape:locked="false" />
</sodipodi:namedview>
<defs
id="defs256" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#d0d0d0;fill-opacity:1;stroke:none;stroke-width:2.03055;stroke-linecap:round;stroke-linejoin:round"
id="rect1970"
width="101.0624"
height="63.537254"
x="58"
y="0" />
<path
style="fill:#d0d0d0;fill-opacity:1;stroke-width:4.48592;stroke-linecap:round;stroke-linejoin:round"
d="M 273.10233,224.90203 145.21711,512 H 76.497509 L 204.38273,224.90203 Z"
id="path829"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#d0d0d0;fill-opacity:1;stroke-width:4.48592;stroke-linecap:round;stroke-linejoin:round"
d="M 81.784799,0 352.78479,512 h 77.27759 L 159.06239,0 Z"
id="rect553-3"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#11ad00;fill-opacity:1;stroke:#11ad00;stroke-width:8;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 177.57694,275.47736 c -10.67459,23.62197 58.48771,42.32845 44.12799,74.56553 l 12.10403,-27.66077 c 14.35971,-32.23708 -54.2799,-50.88656 -43.73232,-74.56553 z"
id="path1073-7"
sodipodi:nodetypes="scccs" />
<path
style="fill:#11ad00;fill-opacity:1;stroke:#11ad00;stroke-width:8;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none"
d="m 105.1005,437.61843 c -10.674586,23.62197 58.48771,42.32845 44.12799,74.56553 l 12.10403,-27.66077 c 14.35971,-32.23708 -54.2799,-50.88656 -43.73232,-74.56553 z"
id="path1073-7-3"
sodipodi:nodetypes="scccs" />
<path
style="fill:#11ad00;fill-opacity:1;stroke:#11ad00;stroke-width:8.03804;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 170.33692,174.65608 c 12.60172,22.70421 77.18453,-12.12069 94.34082,18.78933 l -12.87399,-23.48816 c -17.15629,-30.91003 -81.83366,4.03792 -94.4354,-18.66628 z"
id="path1073-7-9"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#11ad00;fill-opacity:1;stroke:#11ad00;stroke-width:8.03804;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 131.82807,100.21798 c 12.60173,22.70421 77.02729,-12.1207 94.18358,18.78933 L 213.13766,95.51914 c -17.1563,-30.910024 -81.67642,4.03792 -94.27815,-18.666276 z"
id="path1073-7-9-6"
sodipodi:nodetypes="ccccc" />
<ellipse
style="fill:#b7007c;fill-opacity:1;stroke:none;stroke-width:5.93485;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="path2660"
ry="26.699783"
rx="12.302842"
cy="34.928368"
cx="118.63708" />
<ellipse
style="fill:#b7007c;fill-opacity:1;stroke:none;stroke-width:5.93485;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="path2660-2"
ry="26.699783"
rx="12.302842"
cy="-113.73791"
cx="85.984467"
transform="rotate(72)" />
<ellipse
style="fill:#b7007c;fill-opacity:1;stroke:none;stroke-width:5.93485;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="path2660-9"
ry="26.699783"
rx="12.302842"
cy="-128.62366"
cx="-65.495857"
transform="rotate(144)" />
<ellipse
style="fill:#b7007c;fill-opacity:1;stroke:none;stroke-width:5.93485;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="path2660-2-1"
ry="26.699783"
rx="12.302842"
cy="10.842678"
cx="-126.46313"
transform="rotate(-144)" />
<ellipse
style="fill:#b7007c;fill-opacity:1;stroke:none;stroke-width:5.93485;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="path2660-2-1-2"
ry="26.699783"
rx="12.302842"
cy="111.92345"
cx="-12.662658"
transform="rotate(-72)" />
<circle
style="fill:#ffff00;stroke:none;stroke-width:10.3559;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="path2875"
cy="51.855534"
cx="118.63715"
r="12.560751" />
<path
style="fill:#11ad00;fill-opacity:1;stroke:#11ad00;stroke-width:8;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 141.1005,356.61843 c -10.67459,23.62197 58.48771,42.32845 44.12799,74.56553 l 12.10403,-27.66077 c 14.35971,-32.23708 -54.2799,-50.88656 -43.73232,-74.56553 z"
id="path1073-7-6"
sodipodi:nodetypes="scccs" />
<rect
style="fill:#d0d0d0;fill-opacity:1;stroke:none;stroke-width:2.03055;stroke-linecap:round;stroke-linejoin:round"
id="rect1970-6"
width="101.0624"
height="63.537254"
x="352.78479"
y="448.46277" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -18,8 +18,12 @@ use crate::representations::Primitive;
/// Information returned by [Atomic::run]. This mirrors /// Information returned by [Atomic::run]. This mirrors
/// [crate::interpreter::Return] but with a clause instead of an Expr. /// [crate::interpreter::Return] but with a clause instead of an Expr.
pub struct AtomicReturn { pub struct AtomicReturn {
/// The next form of the expression
pub clause: Clause, pub clause: Clause,
/// Remaining gas
pub gas: Option<usize>, pub gas: Option<usize>,
/// Whether further normalization is possible by repeated calls to
/// [Atomic::run]
pub inert: bool, pub inert: bool,
} }
impl AtomicReturn { impl AtomicReturn {
@@ -38,6 +42,7 @@ pub type XfnResult = Result<Clause, RcError>;
/// Errors produced by external code /// Errors produced by external code
pub trait ExternError: Display { pub trait ExternError: Display {
/// Convert into trait object
fn into_extern(self) -> Rc<dyn ExternError> fn into_extern(self) -> Rc<dyn ExternError>
where where
Self: 'static + Sized, Self: 'static + Sized,
@@ -123,21 +128,27 @@ where
/// to pass control back to the interpreter.btop /// to pass control back to the interpreter.btop
pub struct Atom(pub Box<dyn Atomic>); pub struct Atom(pub Box<dyn Atomic>);
impl Atom { impl Atom {
/// Wrap an [Atomic] in a type-erased box
pub fn new<T: 'static + Atomic>(data: T) -> Self { pub fn new<T: 'static + Atomic>(data: T) -> Self {
Self(Box::new(data) as Box<dyn Atomic>) Self(Box::new(data) as Box<dyn Atomic>)
} }
/// Get the contained data
pub fn data(&self) -> &dyn Atomic { pub fn data(&self) -> &dyn Atomic {
self.0.as_ref() as &dyn Atomic self.0.as_ref() as &dyn Atomic
} }
/// Attempt to downcast contained data to a specific type
pub fn try_cast<T: Atomic>(&self) -> Option<&T> { pub fn try_cast<T: Atomic>(&self) -> Option<&T> {
self.data().as_any().downcast_ref() self.data().as_any().downcast_ref()
} }
/// Test the type of the contained data without downcasting
pub fn is<T: 'static>(&self) -> bool { pub fn is<T: 'static>(&self) -> bool {
self.data().as_any().is::<T>() self.data().as_any().is::<T>()
} }
/// Downcast contained data, panic if it isn't the specified type
pub fn cast<T: 'static>(&self) -> &T { pub fn cast<T: 'static>(&self) -> &T {
self.data().as_any().downcast_ref().expect("Type mismatch on Atom::cast") self.data().as_any().downcast_ref().expect("Type mismatch on Atom::cast")
} }
/// Normalize the contained data
pub fn run(&self, ctx: Context) -> AtomicResult { pub fn run(&self, ctx: Context) -> AtomicResult {
self.0.run(ctx) self.0.run(ctx)
} }

View File

@@ -23,6 +23,7 @@ pub trait InternedDisplay {
self.bundle(i).to_string() self.bundle(i).to_string()
} }
/// Combine with an interner to implement [Display]
fn bundle<'a>(&'a self, interner: &'a Interner) -> DisplayBundle<'a, Self> { fn bundle<'a>(&'a self, interner: &'a Interner) -> DisplayBundle<'a, Self> {
DisplayBundle { interner, data: self } DisplayBundle { interner, data: self }
} }

View File

@@ -13,12 +13,15 @@ pub struct Tok<T> {
phantom_data: PhantomData<T>, phantom_data: PhantomData<T>,
} }
impl<T> Tok<T> { impl<T> Tok<T> {
/// Wrap an ID number into a token
pub fn from_id(id: NonZeroU32) -> Self { pub fn from_id(id: NonZeroU32) -> Self {
Self { id, phantom_data: PhantomData } Self { id, phantom_data: PhantomData }
} }
/// Take the ID number out of a token
pub fn into_id(self) -> NonZeroU32 { pub fn into_id(self) -> NonZeroU32 {
self.id self.id
} }
/// Cast into usize
pub fn into_usize(self) -> usize { pub fn into_usize(self) -> usize {
let zero: u32 = self.id.into(); let zero: u32 = self.id.into();
zero as usize zero as usize

View File

@@ -1,3 +1,7 @@
#![deny(missing_docs)]
#![doc(html_logo_url = "../logo.jpg")]
//! Orchid is a lazy, pure scripting language to be embedded in Rust
//! applications. Check out the repo for examples and other links.
pub mod foreign; pub mod foreign;
mod foreign_macros; mod foreign_macros;
pub mod interner; pub mod interner;

View File

@@ -5,7 +5,9 @@ use crate::utils::BoxedIter;
/// Error produced when an import refers to a nonexistent module /// Error produced when an import refers to a nonexistent module
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ModuleNotFound { pub struct ModuleNotFound {
/// The file containing the invalid import
pub file: Vec<String>, pub file: Vec<String>,
/// The invalid import path
pub subpath: Vec<String>, pub subpath: Vec<String>,
} }
impl ProjectError for ModuleNotFound { impl ProjectError for ModuleNotFound {

View File

@@ -7,9 +7,13 @@ use crate::utils::BoxedIter;
/// An import refers to a symbol which exists but is not exported. /// An import refers to a symbol which exists but is not exported.
#[derive(Debug)] #[derive(Debug)]
pub struct NotExported { pub struct NotExported {
/// The containing file - files are always exported
pub file: Vec<String>, pub file: Vec<String>,
/// The path leading to the unexported module
pub subpath: Vec<String>, pub subpath: Vec<String>,
/// The offending file
pub referrer_file: Vec<String>, pub referrer_file: Vec<String>,
/// The module containing the offending import
pub referrer_subpath: Vec<String>, pub referrer_subpath: Vec<String>,
} }
impl ProjectError for NotExported { impl ProjectError for NotExported {

View File

@@ -8,8 +8,11 @@ use crate::utils::BoxedIter;
/// Produced by stages that parse text when it fails. /// Produced by stages that parse text when it fails.
#[derive(Debug)] #[derive(Debug)]
pub struct ParseErrorWithPath { pub struct ParseErrorWithPath {
/// The complete source of the faulty file
pub full_source: String, pub full_source: String,
/// The path to the faulty file
pub path: Vec<String>, pub path: Vec<String>,
/// The parse error produced by Chumsky
pub error: ParseError, pub error: ParseError,
} }
impl ProjectError for ParseErrorWithPath { impl ProjectError for ParseErrorWithPath {

View File

@@ -7,7 +7,9 @@ use crate::utils::BoxedIter;
/// A point of interest in resolving the error, such as the point where /// A point of interest in resolving the error, such as the point where
/// processing got stuck, a command that is likely to be incorrect /// processing got stuck, a command that is likely to be incorrect
pub struct ErrorPosition { pub struct ErrorPosition {
/// The suspected location
pub location: Location, pub location: Location,
/// Any information about the role of this location
pub message: Option<String>, pub message: Option<String>,
} }

View File

@@ -9,8 +9,11 @@ use crate::utils::BoxedIter;
/// than the current module's absolute path /// than the current module's absolute path
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TooManySupers { pub struct TooManySupers {
/// The offending import path
pub path: Vec<String>, pub path: Vec<String>,
/// The file containing the offending import
pub offender_file: Vec<String>, pub offender_file: Vec<String>,
/// The module containing the offending import
pub offender_mod: Vec<String>, pub offender_mod: Vec<String>,
} }
impl ProjectError for TooManySupers { impl ProjectError for TooManySupers {

View File

@@ -6,6 +6,7 @@ use crate::utils::BoxedIter;
/// a path that refers to a directory /// a path that refers to a directory
#[derive(Debug)] #[derive(Debug)]
pub struct UnexpectedDirectory { pub struct UnexpectedDirectory {
/// Path to the offending collection
pub path: Vec<String>, pub path: Vec<String>,
} }
impl ProjectError for UnexpectedDirectory { impl ProjectError for UnexpectedDirectory {

View File

@@ -8,7 +8,9 @@ use crate::utils::BoxedIter;
/// Multiple occurences of the same namespace with different visibility /// Multiple occurences of the same namespace with different visibility
#[derive(Debug)] #[derive(Debug)]
pub struct VisibilityMismatch { pub struct VisibilityMismatch {
/// The namespace with ambiguous visibility
pub namespace: Vec<String>, pub namespace: Vec<String>,
/// The file containing the namespace
pub file: Rc<Vec<String>>, pub file: Rc<Vec<String>>,
} }
impl ProjectError for VisibilityMismatch { impl ProjectError for VisibilityMismatch {

View File

@@ -33,10 +33,14 @@ impl ProjectError for FileLoadingError {
/// as the file system. /// as the file system.
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub enum Loaded { pub enum Loaded {
/// Conceptually equivalent to a sourcefile
Code(Rc<String>), Code(Rc<String>),
/// Conceptually equivalent to the list of *.orc files in a folder, without
/// the extension
Collection(Rc<Vec<String>>), Collection(Rc<Vec<String>>),
} }
impl Loaded { impl Loaded {
/// Is the loaded item source code (not a collection)?
pub fn is_code(&self) -> bool { pub fn is_code(&self) -> bool {
matches!(self, Loaded::Code(_)) matches!(self, Loaded::Code(_))
} }

View File

@@ -16,7 +16,9 @@ use crate::utils::{pushed, Substack};
/// describe libraries of external functions in Rust. It implements [Add] for /// describe libraries of external functions in Rust. It implements [Add] for
/// added convenience /// added convenience
pub enum ConstTree { pub enum ConstTree {
/// A function or constant
Const(Expr), Const(Expr),
/// A submodule
Tree(HashMap<Tok<String>, ConstTree>), Tree(HashMap<Tok<String>, ConstTree>),
} }
impl ConstTree { impl ConstTree {

View File

@@ -19,7 +19,9 @@ use crate::utils::Substack;
/// A [Clause] with associated metadata /// A [Clause] with associated metadata
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Expr { pub struct Expr {
/// The actual value
pub value: Clause, pub value: Clause,
/// Information about the code that produced this value
pub location: Location, pub location: Location,
} }
@@ -87,7 +89,9 @@ pub enum PHClass {
/// Properties of a placeholder that matches unknown tokens in macros /// Properties of a placeholder that matches unknown tokens in macros
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Placeholder { pub struct Placeholder {
/// Identifier to pair placeholders in the pattern and template
pub name: Tok<String>, pub name: Tok<String>,
/// The nature of the token set matched by this placeholder
pub class: PHClass, pub class: PHClass,
} }
@@ -321,8 +325,11 @@ impl InternedDisplay for Clause {
/// A substitution rule as read from the source /// A substitution rule as read from the source
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Rule { pub struct Rule {
/// Tree fragment in the source code that activates this rule
pub pattern: Rc<Vec<Expr>>, pub pattern: Rc<Vec<Expr>>,
/// Influences the order in which rules are checked
pub prio: NotNan<f64>, pub prio: NotNan<f64>,
/// Tree fragment generated by this rule
pub template: Rc<Vec<Expr>>, pub template: Rc<Vec<Expr>>,
} }
@@ -386,7 +393,9 @@ impl InternedDisplay for Rule {
/// A named constant /// A named constant
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Constant { pub struct Constant {
/// Used to reference the constant
pub name: Tok<String>, pub name: Tok<String>,
/// The constant value inserted where the name is found
pub value: Expr, pub value: Expr,
} }

View File

@@ -18,7 +18,9 @@ use crate::utils::sym2string;
/// An expression with metadata /// An expression with metadata
pub struct Expr { pub struct Expr {
/// The actual value
pub clause: Clause, pub clause: Clause,
/// Information about the code that produced this value
pub location: Location, pub location: Location,
} }
@@ -57,10 +59,20 @@ pub struct NotALiteral;
#[derive(Clone)] #[derive(Clone)]
pub struct ExprInst(pub Rc<RefCell<Expr>>); pub struct ExprInst(pub Rc<RefCell<Expr>>);
impl ExprInst { impl ExprInst {
/// Read-only access to the shared expression instance
///
/// # Panics
///
/// if the expression is already borrowed in read-write mode
pub fn expr(&self) -> impl Deref<Target = Expr> + '_ { pub fn expr(&self) -> impl Deref<Target = Expr> + '_ {
self.0.as_ref().borrow() self.0.as_ref().borrow()
} }
/// Read-Write access to the shared expression instance
///
/// # Panics
///
/// if the expression is already borrowed
pub fn expr_mut(&self) -> impl DerefMut<Target = Expr> + '_ { pub fn expr_mut(&self) -> impl DerefMut<Target = Expr> + '_ {
self.0.as_ref().borrow_mut() self.0.as_ref().borrow_mut()
} }
@@ -140,11 +152,23 @@ pub enum Clause {
/// An unintrospectable unit /// An unintrospectable unit
P(Primitive), P(Primitive),
/// A function application /// A function application
Apply { f: ExprInst, x: ExprInst }, Apply {
/// Function to be applied
f: ExprInst,
/// Argument to be substituted in the function
x: ExprInst,
},
/// A name to be looked up in the interpreter's symbol table /// A name to be looked up in the interpreter's symbol table
Constant(Sym), Constant(Sym),
/// A function /// A function
Lambda { args: Option<PathSet>, body: ExprInst }, Lambda {
/// A collection of (zero or more) paths to placeholders belonging to this
/// function
args: Option<PathSet>,
/// The tree produced by this function, with placeholders where the
/// argument will go
body: ExprInst,
},
/// A placeholder within a function that will be replaced upon application /// A placeholder within a function that will be replaced upon application
LambdaArg, LambdaArg,
} }

View File

@@ -6,9 +6,13 @@ use ordered_float::NotNan;
/// external functions /// external functions
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub enum Literal { pub enum Literal {
/// Any floating point number except `NaN`
Num(NotNan<f64>), Num(NotNan<f64>),
/// An unsigned integer; a size, index or pointer
Uint(u64), Uint(u64),
/// A single utf-8 codepoint
Char(char), Char(char),
/// A utf-8 character sequence
Str(String), Str(String),
} }

View File

@@ -8,12 +8,21 @@ use itertools::Itertools;
/// error. Meaningful within the context of a project. /// error. Meaningful within the context of a project.
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Location { pub enum Location {
/// Location information lost or code generated on the fly
Unknown, Unknown,
/// Only the file is known
File(Rc<Vec<String>>), File(Rc<Vec<String>>),
Range { file: Rc<Vec<String>>, range: Range<usize> }, /// Character slice of the code
Range {
/// Argument to the file loading callback that produced this code
file: Rc<Vec<String>>,
/// Index of the unicode code points associated with the code
range: Range<usize>
},
} }
impl Location { impl Location {
/// Range, if known. If the range is known, the file is always known
pub fn range(&self) -> Option<Range<usize>> { pub fn range(&self) -> Option<Range<usize>> {
if let Self::Range { range, .. } = self { if let Self::Range { range, .. } = self {
Some(range.clone()) Some(range.clone())
@@ -22,6 +31,7 @@ impl Location {
} }
} }
/// File, if known
pub fn file(&self) -> Option<Rc<Vec<String>>> { pub fn file(&self) -> Option<Rc<Vec<String>>> {
if let Self::File(file) | Self::Range { file, .. } = self { if let Self::File(file) | Self::Range { file, .. } = self {
Some(file.clone()) Some(file.clone())

View File

@@ -9,6 +9,12 @@ use crate::utils::{unwrap_or, BoxedIter};
/// imported or importing all available symbols with a globstar (*) /// imported or importing all available symbols with a globstar (*)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Import { pub struct Import {
/// Import path, a sequence of module names. Can either start with
///
/// - `self` to reference the current module
/// - any number of `super` to reference the parent module of the implied
/// `self`
/// - a root name
pub path: Sym, pub path: Sym,
/// If name is None, this is a wildcard import /// If name is None, this is a wildcard import
pub name: Option<Tok<String>>, pub name: Option<Tok<String>>,
@@ -31,25 +37,37 @@ impl Import {
/// A namespace block /// A namespace block
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Namespace { pub struct Namespace {
/// Name prefixed to all names in the block
pub name: Tok<String>, pub name: Tok<String>,
/// Prefixed entries
pub body: Vec<FileEntry>, pub body: Vec<FileEntry>,
} }
/// Things that may be prefixed with an export /// Things that may be prefixed with an export
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Member { pub enum Member {
/// A substitution rule. Rules apply even when they're not in scope, if the
/// absolute names are present eg. because they're produced by other rules
Rule(Rule), Rule(Rule),
/// A constant (or function) associated with a name
Constant(Constant), Constant(Constant),
/// A prefixed set of other entries
Namespace(Namespace), Namespace(Namespace),
} }
/// Anything we might encounter in a file /// Anything we might encounter in a file
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum FileEntry { pub enum FileEntry {
/// Imports one or all names in a module
Import(Vec<Import>), Import(Vec<Import>),
/// Comments are kept here in case dev tooling wants to parse documentation
Comment(String), Comment(String),
/// An element visible to the outside
Exported(Member), Exported(Member),
/// An element only visible from local code
Internal(Member), Internal(Member),
/// A list of tokens exported explicitly. This can also create new exported
/// tokens that the local module doesn't actually define a role for
Export(Vec<Tok<String>>), Export(Vec<Tok<String>>),
} }

View File

@@ -10,23 +10,32 @@ use super::sourcefile::Import;
use crate::interner::Tok; use crate::interner::Tok;
use crate::utils::Substack; use crate::utils::Substack;
/// The member in a [ModEntry] which is associated with a name in a [Module]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum ModMember<TItem: Clone, TExt: Clone> { pub enum ModMember<TItem: Clone, TExt: Clone> {
/// Arbitrary data
Item(TItem), Item(TItem),
/// A child module
Sub(Rc<Module<TItem, TExt>>), Sub(Rc<Module<TItem, TExt>>),
} }
/// Data about a name in a [Module]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct ModEntry<TItem: Clone, TExt: Clone> { pub struct ModEntry<TItem: Clone, TExt: Clone> {
/// The submodule or item
pub member: ModMember<TItem, TExt>, pub member: ModMember<TItem, TExt>,
/// Whether the member is visible to modules other than the parent
pub exported: bool, pub exported: bool,
} }
/// A module, containing imports, /// A module, containing imports,
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Module<TItem: Clone, TExt: Clone> { pub struct Module<TItem: Clone, TExt: Clone> {
/// Import statements present this module
pub imports: Vec<Import>, pub imports: Vec<Import>,
/// Submodules and items by name
pub items: HashMap<Tok<String>, ModEntry<TItem, TExt>>, pub items: HashMap<Tok<String>, ModEntry<TItem, TExt>>,
/// Additional information associated with the module
pub extra: TExt, pub extra: TExt,
} }

View File

@@ -46,6 +46,7 @@ pub struct Repository<M: Matcher> {
cache: Vec<(CachedRule<M>, HashSet<Sym>, NotNan<f64>)>, cache: Vec<(CachedRule<M>, HashSet<Sym>, NotNan<f64>)>,
} }
impl<M: Matcher> Repository<M> { impl<M: Matcher> Repository<M> {
/// Build a new repository to hold the given set of rules
pub fn new( pub fn new(
mut rules: Vec<Rule>, mut rules: Vec<Rule>,
i: &Interner, i: &Interner,

View File

@@ -10,7 +10,9 @@ use crate::utils::unwrap_or;
/// An IO command to be handled by the host application. /// An IO command to be handled by the host application.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum IO { pub enum IO {
/// Print a string to standard output and resume execution
Print(String, ExprInst), Print(String, ExprInst),
/// Read a line from standard input and pass it to the calback
Readline(ExprInst), Readline(ExprInst),
} }
atomic_inert!(IO); atomic_inert!(IO);

View File

@@ -6,6 +6,8 @@ use super::str::str;
use crate::interner::Interner; use crate::interner::Interner;
use crate::pipeline::ConstTree; use crate::pipeline::ConstTree;
/// Build the standard library used by the interpreter by combining the other
/// libraries
pub fn mk_stl(i: &Interner) -> ConstTree { pub fn mk_stl(i: &Interner) -> ConstTree {
cpsio(i) + conv(i) + bool(i) + str(i) + num(i) cpsio(i) + conv(i) + bool(i) + str(i) + num(i)
} }

View File

@@ -1,3 +1,4 @@
//! Constants exposed to usercode by the interpreter
mod assertion_error; mod assertion_error;
mod bool; mod bool;
mod conv; mod conv;

View File

@@ -7,7 +7,9 @@ use super::BoxedIter;
/// are technically usable for this purpose, they're very easy to confuse /// are technically usable for this purpose, they're very easy to confuse
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Side { pub enum Side {
/// Left, low, or high-to-low in the case of sequences
Left, Left,
/// Right, high, or low-to-high in the case of sequences
Right, Right,
} }
@@ -21,6 +23,7 @@ impl Display for Side {
} }
impl Side { impl Side {
/// Get the side that is not the current one
pub fn opposite(&self) -> Self { pub fn opposite(&self) -> Self {
match self { match self {
Self::Left => Self::Right, Self::Left => Self::Right,

View File

@@ -17,7 +17,9 @@ pub struct Stackframe<'a, T> {
/// the recursion isn't deep enough to warrant a heap-allocated set. /// the recursion isn't deep enough to warrant a heap-allocated set.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum Substack<'a, T> { pub enum Substack<'a, T> {
/// A level in the linked list
Frame(Stackframe<'a, T>), Frame(Stackframe<'a, T>),
/// The end of the list
Bottom, Bottom,
} }
@@ -33,12 +35,16 @@ impl<'a, T> Substack<'a, T> {
pub fn iter(&self) -> SubstackIterator<T> { pub fn iter(&self) -> SubstackIterator<T> {
SubstackIterator { curr: self } SubstackIterator { curr: self }
} }
/// Add the item to this substack
pub fn push(&'a self, item: T) -> Self { pub fn push(&'a self, item: T) -> Self {
Self::Frame(self.new_frame(item)) Self::Frame(self.new_frame(item))
} }
/// Create a new frame on top of this substack
pub fn new_frame(&'a self, item: T) -> Stackframe<'a, T> { pub fn new_frame(&'a self, item: T) -> Stackframe<'a, T> {
Stackframe { item, prev: self, len: self.opt().map_or(1, |s| s.len) } Stackframe { item, prev: self, len: self.opt().map_or(1, |s| s.len) }
} }
/// obtain the previous stackframe if one exists
/// TODO: this should return a [Substack]
pub fn pop(&'a self, count: usize) -> Option<&'a Stackframe<'a, T>> { pub fn pop(&'a self, count: usize) -> Option<&'a Stackframe<'a, T>> {
if let Self::Frame(p) = self { if let Self::Frame(p) = self {
if count == 0 { if count == 0 {
@@ -50,12 +56,14 @@ impl<'a, T> Substack<'a, T> {
None None
} }
} }
/// number of stackframes
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
match self { match self {
Self::Frame(f) => f.len, Self::Frame(f) => f.len,
Self::Bottom => 0, Self::Bottom => 0,
} }
} }
/// is this the bottom of the stack
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len() == 0 self.len() == 0
} }