add loop examples
This commit is contained in:
parent
6350e4a40f
commit
dbeec4ee76
5 changed files with 110 additions and 49 deletions
4
example/data/hello_world.mc
Normal file
4
example/data/hello_world.mc
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
let msg = "hello world";
|
||||
|
||||
msg
|
22
example/data/loops.mc
Normal file
22
example/data/loops.mc
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
let i = 0;
|
||||
|
||||
loop {
|
||||
i = i + 1;
|
||||
print("i", i);
|
||||
if (i > 5) break;
|
||||
}
|
||||
|
||||
fn for(array, op) {
|
||||
let index = 0;
|
||||
loop {
|
||||
let item = array[index];
|
||||
if (item == none) break;
|
||||
op(item, index);
|
||||
index = index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for([1, 2, 3], (item, index) => {
|
||||
print("at index", index, "item", item);
|
||||
});
|
|
@ -1,15 +1,21 @@
|
|||
use std::{env::args, fs};
|
||||
|
||||
use microlang::Context;
|
||||
use microlang::{Context, Value};
|
||||
|
||||
pub fn main() {
|
||||
unsafe { backtrace_on_stack_overflow::enable() };
|
||||
let mut context = Context::empty();
|
||||
context.define_built("print", |values, _| {
|
||||
for val in values {
|
||||
print!("{} ", val.serialize());
|
||||
}
|
||||
println!();
|
||||
Ok(Value::None)
|
||||
});
|
||||
|
||||
let lines = fs::read_to_string(args().nth(1).expect("Pass a file as arg 1.")).expect("File could not be read.");
|
||||
for line in lines.lines() {
|
||||
match context.eval(line.into()) {
|
||||
match context.eval(lines) {
|
||||
Err(err) => panic!("Failed : {err:?}"),
|
||||
Ok((_, value)) => println!("{}", value.serialize()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
56
src/ast.rs
56
src/ast.rs
|
@ -6,7 +6,7 @@ use crate::{util::Boxable, Context, EvalError, FunImpl, Function, Value};
|
|||
use chumsky::{
|
||||
error::Simple,
|
||||
prelude::{end, just, none_of, one_of, recursive, Recursive},
|
||||
text::{whitespace, TextParser},
|
||||
text::TextParser,
|
||||
Parser,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
|
@ -17,10 +17,7 @@ pub trait Parse<O>: Parser<char, O, Error = Simple<char>> + Clone + 'static {}
|
|||
impl<T: Parser<char, O, Error = Simple<char>> + Clone + 'static, O> Parse<O> for T {}
|
||||
|
||||
fn lx(word: &'static str) -> impl Parse<&'static str> {
|
||||
whitespace()
|
||||
.ignore_then(just(word))
|
||||
.then_ignore(whitespace())
|
||||
.labelled("token")
|
||||
just(word).padded().labelled("token")
|
||||
}
|
||||
|
||||
fn id() -> impl Parse<String> {
|
||||
|
@ -41,8 +38,6 @@ pub struct Block {
|
|||
impl Block {
|
||||
pub fn parser(instr: impl Parse<Instr>, expr: impl Parse<Expr>) -> impl Parse<Self> {
|
||||
instr
|
||||
.clone()
|
||||
.then_ignore(lx(";"))
|
||||
.repeated()
|
||||
.then(expr.map(Boxable::to_box).or_not())
|
||||
.map(|(instructions, expression)| Self {
|
||||
|
@ -97,6 +92,7 @@ impl FunDef {
|
|||
pub fn parser_lamb(instr: impl Parse<Instr>, expr: impl Parse<Expr>) -> impl Parse<Self> {
|
||||
let arguments = id().padded().separated_by(lx(","));
|
||||
(lx("(").ignore_then(arguments).then_ignore(lx(")")))
|
||||
.then_ignore(lx("=>"))
|
||||
.then(lx("{").ignore_then(Block::parser(instr, expr)).then_ignore(lx("}")))
|
||||
.map(|(args, body)| Self { args, body })
|
||||
.labelled("lambda")
|
||||
|
@ -121,27 +117,30 @@ pub enum Instr {
|
|||
impl Instr {
|
||||
pub fn parser(expr: impl Parse<Expr>) -> impl Parse<Self> {
|
||||
recursive(|instr: Recursive<'_, _, Self, _>| {
|
||||
(lx("{")
|
||||
(lx(";").map(|_| Self::Nop).labelled("no operation"))
|
||||
.or(lx("{")
|
||||
.ignore_then(Block::parser(instr.clone(), expr.clone()))
|
||||
.then_ignore(lx("}"))
|
||||
.map(Self::Block))
|
||||
.labelled("block instruction")
|
||||
.map(Self::Block)
|
||||
.labelled("block instruction"))
|
||||
.or(lx("let")
|
||||
.ignore_then(id())
|
||||
.then_ignore(lx("="))
|
||||
.then(expr.clone())
|
||||
.map(|(id, ex)| Self::Init(id, ex)))
|
||||
.labelled("variable initialization")
|
||||
.then_ignore(lx(";"))
|
||||
.map(|(id, ex)| Self::Init(id, ex))
|
||||
.labelled("variable initialization"))
|
||||
.or(lx("if")
|
||||
.ignore_then(lx("(").ignore_then(expr.clone()).then_ignore(lx(")")))
|
||||
.then((instr.clone()).then((lx("else").ignore_then(instr.clone())).or_not()))
|
||||
.map(|(cond, (then, els))| Self::Branch(cond, then.to_box(), els.unwrap_or(Instr::Nop).to_box())))
|
||||
.labelled("condition instruction")
|
||||
.map(|(cond, (then, els))| Self::Branch(cond, then.to_box(), els.unwrap_or(Instr::Nop).to_box()))
|
||||
.labelled("condition instruction"))
|
||||
.or(lx("loop")
|
||||
.ignore_then(instr.clone())
|
||||
.map(|body| Self::Loop(body.to_box())))
|
||||
.labelled("loop instruction")
|
||||
.map(|body| Self::Loop(body.to_box()))
|
||||
.labelled("loop instruction"))
|
||||
.or(ShortDef::parser(expr.clone())
|
||||
.then_ignore(lx(";"))
|
||||
.map(Self::Short)
|
||||
.labelled("shortcut instruction"))
|
||||
.or(FunDef::parser_def(instr, expr.clone())
|
||||
|
@ -150,9 +149,10 @@ impl Instr {
|
|||
.or(id()
|
||||
.then_ignore(lx("="))
|
||||
.then(expr.clone())
|
||||
.then_ignore(lx(";"))
|
||||
.map(|(id, ex)| Self::Assign(id, ex))
|
||||
.labelled("variable assigniation."))
|
||||
.or(expr.map(Self::Expr))
|
||||
.labelled("variable assigniation"))
|
||||
.or(expr.then_ignore(lx(";")).map(Self::Expr))
|
||||
})
|
||||
.labelled("instruction")
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ impl Instr {
|
|||
Self::Expr(expr) => no_short(expr.eval(context)?),
|
||||
Self::Init(name, expr) => {
|
||||
let value = expr.eval(context)?;
|
||||
context.scope().borrow_mut().append(name.clone(), value);
|
||||
context.scope().borrow_mut().define(name.clone(), value);
|
||||
no_short(())
|
||||
}
|
||||
Self::Assign(name, expr) => {
|
||||
|
@ -262,7 +262,7 @@ impl Expr {
|
|||
.map(|(e, a)| Self::Access(e.to_box(), a)))
|
||||
.or((left.clone())
|
||||
.then_ignore(lx("("))
|
||||
.then(expr.clone().then_ignore(lx(",")).repeated())
|
||||
.then(expr.clone().separated_by(lx(",")))
|
||||
.then_ignore(lx(")"))
|
||||
.map(|(e, a)| Self::Call(e.to_box(), a)))
|
||||
.or((left.clone())
|
||||
|
@ -354,6 +354,21 @@ impl Op {
|
|||
Ok(match (self, l, r) {
|
||||
(Self::Add, Value::Str(l), Value::Str(r)) => Value::Str(format!("{l}{r}")),
|
||||
(Self::Add, Value::Num(l), Value::Num(r)) => Value::Num(l + r),
|
||||
(Self::Sub, Value::Num(l), Value::Num(r)) => Value::Num(l - r),
|
||||
(Self::Div, Value::Num(l), Value::Num(r)) => Value::Num(l / r),
|
||||
(Self::Prod, Value::Num(l), Value::Num(r)) => Value::Num(l * r),
|
||||
(Self::Lt, Value::Num(l), Value::Num(r)) => Value::Bool(l < r),
|
||||
(Self::Gt, Value::Num(l), Value::Num(r)) => Value::Bool(l > r),
|
||||
(Self::Leq, Value::Num(l), Value::Num(r)) => Value::Bool(l <= r),
|
||||
(Self::Geq, Value::Num(l), Value::Num(r)) => Value::Bool(l >= r),
|
||||
(Self::Eq, Value::None, Value::None) => Value::Bool(true),
|
||||
(Self::Eq, Value::Num(l), Value::Num(r)) => Value::Bool(l == r),
|
||||
(Self::Eq, Value::Str(l), Value::Str(r)) => Value::Bool(l == r),
|
||||
(Self::Eq, Value::Array(l), Value::Array(r)) => Value::Bool(Rc::ptr_eq(l, r)),
|
||||
(Self::Eq, Value::Object(l), Value::Object(r)) => Value::Bool(Rc::ptr_eq(l, r)),
|
||||
(Self::Eq, Value::Function(l), Value::Function(r)) => Value::Bool(Rc::ptr_eq(l, r)),
|
||||
(Self::Eq, _, _) => Value::Bool(false),
|
||||
(Self::Neq, _, _) => UniOp::Inv.apply(&Self::Eq.apply(l, r)?)?,
|
||||
_ => Err(EvalError::WrongType)?,
|
||||
})
|
||||
}
|
||||
|
@ -400,6 +415,7 @@ impl Litteral {
|
|||
.ignore_then(char.repeated())
|
||||
.then_ignore(just("\""))
|
||||
.map(|s| Self::Str(s.iter().collect())))
|
||||
.or(just("none").map(|_| Self::None))
|
||||
.or(just("true")
|
||||
.map(|_| true)
|
||||
.or(just("false").map(|_| false))
|
||||
|
|
17
src/lib.rs
17
src/lib.rs
|
@ -53,6 +53,19 @@ impl Context {
|
|||
Ok((parsed, value))
|
||||
}
|
||||
|
||||
pub fn define(&mut self, name: impl ToString, value: Value) {
|
||||
self.scope().borrow_mut().define(name.to_string(), value)
|
||||
}
|
||||
|
||||
pub fn define_built(&mut self, name: impl ToString, op: impl Fn(Vec<Value>, &mut Context) -> FunRes + 'static) {
|
||||
let def = FunImpl::Built(Rc::new(op) as Rc<BuiltFun>);
|
||||
let function = Function {
|
||||
capturing: Rc::new(RefCell::new(Scope::new(None))),
|
||||
def,
|
||||
};
|
||||
self.define(name.to_string(), Value::Function(Rc::new(RefCell::new(function))))
|
||||
}
|
||||
|
||||
pub fn scope(&self) -> Rc<RefCell<Scope>> {
|
||||
self.frame.clone()
|
||||
}
|
||||
|
@ -88,7 +101,7 @@ impl Scope {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn append(&mut self, name: String, value: Value) {
|
||||
pub fn define(&mut self, name: String, value: Value) {
|
||||
self.defs.insert(name, value);
|
||||
}
|
||||
|
||||
|
@ -209,7 +222,7 @@ impl Function {
|
|||
FunImpl::Def(def) => Scope::alt(context, self.capturing.clone(), |context| {
|
||||
let names = def.args.iter().cloned();
|
||||
for (name, value) in names.zip(args.into_iter().chain(repeat(Value::None))) {
|
||||
context.scope().borrow_mut().append(name, value);
|
||||
context.scope().borrow_mut().define(name, value);
|
||||
}
|
||||
match def.body.eval(context) {
|
||||
Err(err) => Err(err),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue