add export keyword
This commit is contained in:
@@ -56,7 +56,7 @@ You can create a multi-statement expression using either `()` syntax or the `~`
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Global Scope (unimplemented)
|
### Global Scope
|
||||||
|
|
||||||
You can introduce a variable to global scope using the `export` builtin function.
|
You can introduce a variable to global scope using the `export` builtin function.
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ where
|
|||||||
I: Iterator<Item = Result<ParseTree, ParseError>>
|
I: Iterator<Item = Result<ParseTree, ParseError>>
|
||||||
{
|
{
|
||||||
exprs: &'a mut I,
|
exprs: &'a mut I,
|
||||||
globals: HashMap<String, Object>,
|
globals: &'a mut HashMap<String, Object>,
|
||||||
locals: HashMap<String, Object>,
|
locals: HashMap<String, Object>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,20 +57,15 @@ impl<'a, I> Executor<'a, I>
|
|||||||
where
|
where
|
||||||
I: Iterator<Item = Result<ParseTree, ParseError>>,
|
I: Iterator<Item = Result<ParseTree, ParseError>>,
|
||||||
{
|
{
|
||||||
pub fn new(exprs: &'a mut I) -> Self {
|
pub fn new(exprs: &'a mut I, globals: &'a mut HashMap<String, Object>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
exprs,
|
exprs,
|
||||||
globals: HashMap::new(),
|
globals,
|
||||||
locals: HashMap::new(),
|
locals: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn globals(mut self, globals: HashMap<String, Object>) -> Self {
|
pub fn _add_global(self, k: String, v: Object) -> Self {
|
||||||
self.globals = globals;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn _add_global(mut self, k: String, v: Object) -> Self {
|
|
||||||
self.globals.insert(k, v);
|
self.globals.insert(k, v);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -237,11 +232,11 @@ where
|
|||||||
Err(RuntimeError::ImmutableError(ident.clone()))
|
Err(RuntimeError::ImmutableError(ident.clone()))
|
||||||
} else {
|
} else {
|
||||||
let value = self.exec(body)?;
|
let value = self.exec(body)?;
|
||||||
|
let g = self.globals.clone();
|
||||||
|
|
||||||
Executor::new(self.exprs)
|
Executor::new(self.exprs, &mut self.globals)
|
||||||
.globals(self.globals.clone())
|
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone())
|
||||||
.add_local(ident, Object::value(value, self.globals.to_owned(), self.locals.to_owned()))
|
.add_local(ident, Object::value(value, g, self.locals.to_owned()))
|
||||||
.exec(scope)
|
.exec(scope)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -249,18 +244,18 @@ where
|
|||||||
if self.variable_exists(&ident) {
|
if self.variable_exists(&ident) {
|
||||||
Err(RuntimeError::ImmutableError(ident.clone()))
|
Err(RuntimeError::ImmutableError(ident.clone()))
|
||||||
} else {
|
} else {
|
||||||
Executor::new(self.exprs)
|
let g = self.globals.clone();
|
||||||
.globals(self.globals.clone())
|
Executor::new(self.exprs, &mut self.globals)
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone())
|
||||||
.add_local(ident, Object::variable(*body, self.globals.to_owned(), self.locals.to_owned()))
|
.add_local(ident, Object::variable(*body, g, self.locals.to_owned()))
|
||||||
.exec(scope)
|
.exec(scope)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ParseTree::FunctionDefinition(func, scope) => {
|
ParseTree::FunctionDefinition(func, scope) => {
|
||||||
Executor::new(self.exprs)
|
let g = self.globals.clone();
|
||||||
.globals(self.globals.clone())
|
Executor::new(self.exprs, &mut self.globals)
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone())
|
||||||
.add_local(func.name().unwrap().to_string(), Object::function(func, self.globals.clone(), self.locals.clone()))
|
.add_local(func.name().unwrap().to_string(), Object::function(func, g, self.locals.clone()))
|
||||||
.exec(scope)
|
.exec(scope)
|
||||||
},
|
},
|
||||||
ParseTree::Compose(x, y) => {
|
ParseTree::Compose(x, y) => {
|
||||||
@@ -376,6 +371,14 @@ where
|
|||||||
t => Err(RuntimeError::NoOverloadForTypes("fini".into(), vec![t]))
|
t => Err(RuntimeError::NoOverloadForTypes("fini".into(), vec![t]))
|
||||||
},
|
},
|
||||||
ParseTree::Nop => Ok(Value::Nil),
|
ParseTree::Nop => Ok(Value::Nil),
|
||||||
|
ParseTree::Export(names) => {
|
||||||
|
for name in names {
|
||||||
|
let obj = self.locals.remove(&name).ok_or(RuntimeError::VariableUndefined(name.clone()))?;
|
||||||
|
self.globals.insert(name, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::Nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,22 +50,22 @@ impl Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn call(&mut self,
|
pub(crate) fn call(&mut self,
|
||||||
globals: HashMap<String, Object>,
|
mut globals: HashMap<String, Object>,
|
||||||
locals: HashMap<String, Object>,
|
locals: HashMap<String, Object>,
|
||||||
args: Vec<Object>) -> Result<Value, RuntimeError>
|
args: Vec<Object>) -> Result<Value, RuntimeError>
|
||||||
{
|
{
|
||||||
let mut tree = vec![Ok(*self.body.clone())].into_iter();
|
let mut tree = vec![Ok(*self.body.clone())].into_iter();
|
||||||
|
let g = globals.clone();
|
||||||
|
|
||||||
let mut exec = Executor::new(&mut tree)
|
let mut exec = Executor::new(&mut tree, &mut globals)
|
||||||
.locals(locals.clone())
|
.locals(locals.clone());
|
||||||
.globals(globals.clone());
|
|
||||||
|
|
||||||
for (obj, name) in std::iter::zip(args.into_iter(), self.arg_names.clone().into_iter()) {
|
for (obj, name) in std::iter::zip(args.into_iter(), self.arg_names.clone().into_iter()) {
|
||||||
exec = exec.add_local(name.clone(), obj);
|
exec = exec.add_local(name.clone(), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(name) = self.name().map(|x| x.to_string()) {
|
if let Some(name) = self.name().map(|x| x.to_string()) {
|
||||||
exec = exec.add_local(name, Object::function(self.clone(), globals, locals));
|
exec = exec.add_local(name, Object::function(self.clone(), g, locals));
|
||||||
}
|
}
|
||||||
|
|
||||||
exec.next().unwrap()
|
exec.next().unwrap()
|
||||||
|
|||||||
16
src/lib.rs
16
src/lib.rs
@@ -13,7 +13,6 @@ use std::fmt::Display;
|
|||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
@@ -139,9 +138,8 @@ impl Object {
|
|||||||
Cache::Uncached(tree) => {
|
Cache::Uncached(tree) => {
|
||||||
let mut tree = vec![Ok(tree)].into_iter();
|
let mut tree = vec![Ok(tree)].into_iter();
|
||||||
|
|
||||||
let mut exec = Executor::new(&mut tree)
|
let mut exec = Executor::new(&mut tree, &mut self.globals)
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone());
|
||||||
.globals(self.globals.clone());
|
|
||||||
|
|
||||||
let v = exec.next().unwrap()?;
|
let v = exec.next().unwrap()?;
|
||||||
|
|
||||||
@@ -163,21 +161,23 @@ impl Object {
|
|||||||
|
|
||||||
pub struct Runtime<'a, R: BufRead> {
|
pub struct Runtime<'a, R: BufRead> {
|
||||||
tokenizer: Peekable<Tokenizer<R>>,
|
tokenizer: Peekable<Tokenizer<R>>,
|
||||||
|
global_types: HashMap<String, Type>,
|
||||||
|
globals: HashMap<String, Object>,
|
||||||
parser: Option<Parser<'a, Tokenizer<R>>>,
|
parser: Option<Parser<'a, Tokenizer<R>>>,
|
||||||
phantom: PhantomData<Executor<'a, Parser<'a, Tokenizer<R>>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: BufRead> Runtime<'a, R> {
|
impl<'a, R: BufRead> Runtime<'a, R> {
|
||||||
pub fn new(reader: R) -> Self {
|
pub fn new(reader: R) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tokenizer: Tokenizer::new(reader).peekable(),
|
tokenizer: Tokenizer::new(reader).peekable(),
|
||||||
|
global_types: HashMap::new(),
|
||||||
|
globals: HashMap::new(),
|
||||||
parser: None,
|
parser: None,
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn values(&'a mut self) -> impl Iterator<Item = Result<Value, RuntimeError>> + 'a {
|
pub fn values(&'a mut self) -> impl Iterator<Item = Result<Value, RuntimeError>> + 'a {
|
||||||
self.parser = Some(Parser::new(&mut self.tokenizer));
|
self.parser = Some(Parser::new(&mut self.tokenizer, &mut self.global_types));
|
||||||
Executor::new(self.parser.as_mut().unwrap())
|
Executor::new(self.parser.as_mut().unwrap(), &mut self.globals)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
|
||||||
|
use crate::executor::Executor;
|
||||||
|
|
||||||
use super::{Value, Type, Function, FunctionType};
|
use super::{Value, Type, Function, FunctionType};
|
||||||
use super::tokenizer::{Token, TokenizeError, Op};
|
use super::tokenizer::{Token, TokenizeError, Op};
|
||||||
|
|
||||||
|
use std::borrow::{BorrowMut, Cow};
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
@@ -90,31 +93,32 @@ pub(crate) enum ParseTree {
|
|||||||
// Misc
|
// Misc
|
||||||
Print(Box<ParseTree>),
|
Print(Box<ParseTree>),
|
||||||
Nop,
|
Nop,
|
||||||
|
Export(Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses input tokens and produces ParseTrees for an Executor
|
/// Parses input tokens and produces ParseTrees for an Executor
|
||||||
pub(crate) struct Parser<'a, I: Iterator<Item = Result<Token, TokenizeError>>> {
|
pub(crate) struct Parser<'a, I: Iterator<Item = Result<Token, TokenizeError>>> {
|
||||||
tokens: &'a mut Peekable<I>,
|
tokens: &'a mut Peekable<I>,
|
||||||
globals: HashMap<String, Type>,
|
globals: &'a mut HashMap<String, Type>,
|
||||||
locals: HashMap<String, Type>,
|
locals: HashMap<String, Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
||||||
pub fn new(tokens: &'a mut Peekable<I>) -> Self {
|
pub fn new(tokens: &'a mut Peekable<I>, globals: &'a mut HashMap<String, Type>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tokens: tokens,
|
tokens: tokens,
|
||||||
globals: HashMap::new(),
|
globals,
|
||||||
locals: HashMap::new()
|
locals: HashMap::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn globals(mut self, globals: HashMap<String, Type>) -> Self {
|
pub fn add_global(self, k: String, v: Type) -> Self {
|
||||||
self.globals = globals;
|
self.globals.insert(k, v);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _add_global(mut self, k: String, v: Type) -> Self {
|
pub fn add_globals<Items: Iterator<Item = (String, Type)>>(self, items: Items) -> Self {
|
||||||
self.globals.insert(k, v);
|
items.for_each(|(name, t)| _ = self.globals.insert(name, t));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,11 +132,20 @@ impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_locals<Items: Iterator<Item = (String, Type)>>(mut self, items: Items) -> Self {
|
||||||
|
items.for_each(|(name, t)| _ = self.locals.insert(name, t));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn get_object_type(&self, ident: &String) -> Result<&Type, ParseError> {
|
fn get_object_type(&self, ident: &String) -> Result<&Type, ParseError> {
|
||||||
self.locals.get(ident).or(self.globals.get(ident))
|
self.locals.get(ident).or(self.globals.get(ident))
|
||||||
.ok_or(ParseError::IdentifierUndefined(ident.clone()))
|
.ok_or(ParseError::IdentifierUndefined(ident.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_object_types<Names: Iterator<Item = String>>(&self, items: Names) -> impl Iterator<Item = Result<&Type, ParseError>> {
|
||||||
|
items.map(|x| self.get_object_type(&x))
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(&mut self) -> Result<ParseTree, ParseError> {
|
fn parse(&mut self) -> Result<ParseTree, ParseError> {
|
||||||
match self.tokens.next().ok_or(ParseError::NoInput)?.map_err(|e| ParseError::TokenizeError(e))? {
|
match self.tokens.next().ok_or(ParseError::NoInput)?.map_err(|e| ParseError::TokenizeError(e))? {
|
||||||
Token::Constant(c) => Ok(ParseTree::Constant(c)),
|
Token::Constant(c) => Ok(ParseTree::Constant(c)),
|
||||||
@@ -165,18 +178,16 @@ impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
|||||||
if let Token::Identifier(ident) = token {
|
if let Token::Identifier(ident) = token {
|
||||||
match op {
|
match op {
|
||||||
Op::Equ => Ok(ParseTree::Equ(ident.clone(),
|
Op::Equ => Ok(ParseTree::Equ(ident.clone(),
|
||||||
body.clone(),
|
body,
|
||||||
Box::new(Parser::new(self.tokens.by_ref())
|
Box::new(Parser::new(self.tokens.by_ref(), self.globals.borrow_mut())
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone())
|
||||||
.globals(self.globals.clone())
|
|
||||||
.add_local(ident, Type::Any)
|
.add_local(ident, Type::Any)
|
||||||
.parse()?))
|
.parse()?))
|
||||||
),
|
),
|
||||||
Op::LazyEqu => Ok(ParseTree::LazyEqu(ident.clone(),
|
Op::LazyEqu => Ok(ParseTree::LazyEqu(ident.clone(),
|
||||||
body.clone(),
|
body,
|
||||||
Box::new(Parser::new(self.tokens.by_ref())
|
Box::new(Parser::new(self.tokens.by_ref(), self.globals.borrow_mut())
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone())
|
||||||
.globals(self.globals.clone())
|
|
||||||
.add_local(ident, Type::Any)
|
.add_local(ident, Type::Any)
|
||||||
.parse()?))
|
.parse()?))
|
||||||
),
|
),
|
||||||
@@ -191,8 +202,7 @@ impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
|||||||
|
|
||||||
Ok(ParseTree::FunctionDefinition(f.clone(),
|
Ok(ParseTree::FunctionDefinition(f.clone(),
|
||||||
Box::new(
|
Box::new(
|
||||||
Parser::new(self.tokens)
|
Parser::new(self.tokens, self.globals.borrow_mut())
|
||||||
.globals(self.globals.clone())
|
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone())
|
||||||
.add_local(f.name().unwrap().to_string(), Type::Function(f.get_type()))
|
.add_local(f.name().unwrap().to_string(), Type::Function(f.get_type()))
|
||||||
.parse()?
|
.parse()?
|
||||||
@@ -237,8 +247,7 @@ impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|
||||||
let trees: Vec<ParseTree> = Parser::new(&mut array_tokens)
|
let trees: Vec<ParseTree> = Parser::new(&mut array_tokens, self.globals.borrow_mut())
|
||||||
.globals(self.globals.to_owned())
|
|
||||||
.locals(self.locals.to_owned())
|
.locals(self.locals.to_owned())
|
||||||
.collect::<Result<_, ParseError>>()?;
|
.collect::<Result<_, ParseError>>()?;
|
||||||
|
|
||||||
@@ -273,8 +282,7 @@ impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|
||||||
let trees: Vec<ParseTree> = Parser::new(&mut tokens)
|
let trees: Vec<ParseTree> = Parser::new(&mut tokens, self.globals.borrow_mut())
|
||||||
.globals(self.globals.to_owned())
|
|
||||||
.locals(self.locals.to_owned())
|
.locals(self.locals.to_owned())
|
||||||
.collect::<Result<_, ParseError>>()?;
|
.collect::<Result<_, ParseError>>()?;
|
||||||
|
|
||||||
@@ -302,6 +310,27 @@ impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
|||||||
Op::Tail => Ok(ParseTree::Tail(Box::new(self.parse()?))),
|
Op::Tail => Ok(ParseTree::Tail(Box::new(self.parse()?))),
|
||||||
Op::Init => Ok(ParseTree::Init(Box::new(self.parse()?))),
|
Op::Init => Ok(ParseTree::Init(Box::new(self.parse()?))),
|
||||||
Op::Fini => Ok(ParseTree::Fini(Box::new(self.parse()?))),
|
Op::Fini => Ok(ParseTree::Fini(Box::new(self.parse()?))),
|
||||||
|
Op::Export => {
|
||||||
|
let list = self.parse()?;
|
||||||
|
let mut g = HashMap::new();
|
||||||
|
let list = Executor::new(&mut vec![Ok(list)].into_iter(), &mut g).next().unwrap().map_err(|_| ParseError::NoInput)?;
|
||||||
|
|
||||||
|
if let Value::Array(Type::String, items) = list {
|
||||||
|
let names = items.into_iter().map(|x| match x {
|
||||||
|
Value::String(s) => s,
|
||||||
|
_ => unreachable!(),
|
||||||
|
});
|
||||||
|
|
||||||
|
for name in names.clone() {
|
||||||
|
let t = self.locals.remove(&name).ok_or(ParseError::IdentifierUndefined(name.clone()))?;
|
||||||
|
self.globals.insert(name, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ParseTree::Export(names.collect()))
|
||||||
|
} else {
|
||||||
|
Err(ParseError::NoInput)
|
||||||
|
}
|
||||||
|
}
|
||||||
op => Err(ParseError::UnwantedToken(Token::Operator(op))),
|
op => Err(ParseError::UnwantedToken(Token::Operator(op))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -319,8 +348,7 @@ impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(Function::lambda(t, args, Box::new(
|
Ok(Function::lambda(t, args, Box::new(
|
||||||
Parser::new(self.tokens)
|
Parser::new(self.tokens, &mut self.globals)
|
||||||
.globals(self.globals.clone())
|
|
||||||
.locals(locals).parse()?)))
|
.locals(locals).parse()?)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,8 +365,7 @@ impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
|||||||
locals.insert(name.clone(), Type::Function(t.clone()));
|
locals.insert(name.clone(), Type::Function(t.clone()));
|
||||||
|
|
||||||
Ok(Function::named(&name, t, args, Box::new(
|
Ok(Function::named(&name, t, args, Box::new(
|
||||||
Parser::new(self.tokens)
|
Parser::new(self.tokens, &mut self.globals)
|
||||||
.globals(self.globals.clone())
|
|
||||||
.locals(locals).parse()?)))
|
.locals(locals).parse()?)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ pub enum Op {
|
|||||||
Tail,
|
Tail,
|
||||||
Init,
|
Init,
|
||||||
Fini,
|
Fini,
|
||||||
|
Export,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@@ -128,6 +129,7 @@ impl Token {
|
|||||||
"tail" => Ok(Token::Operator(Op::Tail)),
|
"tail" => Ok(Token::Operator(Op::Tail)),
|
||||||
"init" => Ok(Token::Operator(Op::Init)),
|
"init" => Ok(Token::Operator(Op::Init)),
|
||||||
"fini" => Ok(Token::Operator(Op::Fini)),
|
"fini" => Ok(Token::Operator(Op::Fini)),
|
||||||
|
"export" => Ok(Token::Operator(Op::Export)),
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
"Any" => Ok(Token::Type(Type::Any)),
|
"Any" => Ok(Token::Type(Type::Any)),
|
||||||
@@ -412,4 +414,20 @@ impl<R: BufRead> std::iter::Iterator for Tokenizer<R> {
|
|||||||
Err(e) => Some(Err(TokenizeError::IO(e))),
|
Err(e) => Some(Err(TokenizeError::IO(e))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a() {
|
||||||
|
let program = ":. map : f .? x [Any] -> [Any]";
|
||||||
|
|
||||||
|
let tokens: Vec<Token> = Tokenizer::from_str(program).unwrap().collect::<Result<_, _>>().unwrap();
|
||||||
|
|
||||||
|
println!("{tokens:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user