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 std::{env::args, fs};
|
||||||
|
|
||||||
use microlang::Context;
|
use microlang::{Context, Value};
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
unsafe { backtrace_on_stack_overflow::enable() };
|
unsafe { backtrace_on_stack_overflow::enable() };
|
||||||
let mut context = Context::empty();
|
let mut context = Context::empty();
|
||||||
let lines = fs::read_to_string(args().nth(1).expect("Pass a file as arg 1.")).expect("File could not be read.");
|
context.define_built("print", |values, _| {
|
||||||
for line in lines.lines() {
|
for val in values {
|
||||||
match context.eval(line.into()) {
|
print!("{} ", val.serialize());
|
||||||
Err(err) => panic!("Failed : {err:?}"),
|
|
||||||
Ok((_, value)) => println!("{}", value.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.");
|
||||||
|
match context.eval(lines) {
|
||||||
|
Err(err) => panic!("Failed : {err:?}"),
|
||||||
|
Ok((_, value)) => println!("{}", value.serialize()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
98
src/ast.rs
98
src/ast.rs
|
@ -6,7 +6,7 @@ use crate::{util::Boxable, Context, EvalError, FunImpl, Function, Value};
|
||||||
use chumsky::{
|
use chumsky::{
|
||||||
error::Simple,
|
error::Simple,
|
||||||
prelude::{end, just, none_of, one_of, recursive, Recursive},
|
prelude::{end, just, none_of, one_of, recursive, Recursive},
|
||||||
text::{whitespace, TextParser},
|
text::TextParser,
|
||||||
Parser,
|
Parser,
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
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 {}
|
impl<T: Parser<char, O, Error = Simple<char>> + Clone + 'static, O> Parse<O> for T {}
|
||||||
|
|
||||||
fn lx(word: &'static str) -> impl Parse<&'static str> {
|
fn lx(word: &'static str) -> impl Parse<&'static str> {
|
||||||
whitespace()
|
just(word).padded().labelled("token")
|
||||||
.ignore_then(just(word))
|
|
||||||
.then_ignore(whitespace())
|
|
||||||
.labelled("token")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id() -> impl Parse<String> {
|
fn id() -> impl Parse<String> {
|
||||||
|
@ -41,8 +38,6 @@ pub struct Block {
|
||||||
impl Block {
|
impl Block {
|
||||||
pub fn parser(instr: impl Parse<Instr>, expr: impl Parse<Expr>) -> impl Parse<Self> {
|
pub fn parser(instr: impl Parse<Instr>, expr: impl Parse<Expr>) -> impl Parse<Self> {
|
||||||
instr
|
instr
|
||||||
.clone()
|
|
||||||
.then_ignore(lx(";"))
|
|
||||||
.repeated()
|
.repeated()
|
||||||
.then(expr.map(Boxable::to_box).or_not())
|
.then(expr.map(Boxable::to_box).or_not())
|
||||||
.map(|(instructions, expression)| Self {
|
.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> {
|
pub fn parser_lamb(instr: impl Parse<Instr>, expr: impl Parse<Expr>) -> impl Parse<Self> {
|
||||||
let arguments = id().padded().separated_by(lx(","));
|
let arguments = id().padded().separated_by(lx(","));
|
||||||
(lx("(").ignore_then(arguments).then_ignore(lx(")")))
|
(lx("(").ignore_then(arguments).then_ignore(lx(")")))
|
||||||
|
.then_ignore(lx("=>"))
|
||||||
.then(lx("{").ignore_then(Block::parser(instr, expr)).then_ignore(lx("}")))
|
.then(lx("{").ignore_then(Block::parser(instr, expr)).then_ignore(lx("}")))
|
||||||
.map(|(args, body)| Self { args, body })
|
.map(|(args, body)| Self { args, body })
|
||||||
.labelled("lambda")
|
.labelled("lambda")
|
||||||
|
@ -121,38 +117,42 @@ pub enum Instr {
|
||||||
impl Instr {
|
impl Instr {
|
||||||
pub fn parser(expr: impl Parse<Expr>) -> impl Parse<Self> {
|
pub fn parser(expr: impl Parse<Expr>) -> impl Parse<Self> {
|
||||||
recursive(|instr: Recursive<'_, _, Self, _>| {
|
recursive(|instr: Recursive<'_, _, Self, _>| {
|
||||||
(lx("{")
|
(lx(";").map(|_| Self::Nop).labelled("no operation"))
|
||||||
.ignore_then(Block::parser(instr.clone(), expr.clone()))
|
.or(lx("{")
|
||||||
.then_ignore(lx("}"))
|
.ignore_then(Block::parser(instr.clone(), expr.clone()))
|
||||||
.map(Self::Block))
|
.then_ignore(lx("}"))
|
||||||
.labelled("block instruction")
|
.map(Self::Block)
|
||||||
.or(lx("let")
|
.labelled("block instruction"))
|
||||||
.ignore_then(id())
|
.or(lx("let")
|
||||||
.then_ignore(lx("="))
|
.ignore_then(id())
|
||||||
.then(expr.clone())
|
.then_ignore(lx("="))
|
||||||
.map(|(id, ex)| Self::Init(id, ex)))
|
.then(expr.clone())
|
||||||
.labelled("variable initialization")
|
.then_ignore(lx(";"))
|
||||||
.or(lx("if")
|
.map(|(id, ex)| Self::Init(id, ex))
|
||||||
.ignore_then(lx("(").ignore_then(expr.clone()).then_ignore(lx(")")))
|
.labelled("variable initialization"))
|
||||||
.then((instr.clone()).then((lx("else").ignore_then(instr.clone())).or_not()))
|
.or(lx("if")
|
||||||
.map(|(cond, (then, els))| Self::Branch(cond, then.to_box(), els.unwrap_or(Instr::Nop).to_box())))
|
.ignore_then(lx("(").ignore_then(expr.clone()).then_ignore(lx(")")))
|
||||||
.labelled("condition instruction")
|
.then((instr.clone()).then((lx("else").ignore_then(instr.clone())).or_not()))
|
||||||
.or(lx("loop")
|
.map(|(cond, (then, els))| Self::Branch(cond, then.to_box(), els.unwrap_or(Instr::Nop).to_box()))
|
||||||
.ignore_then(instr.clone())
|
.labelled("condition instruction"))
|
||||||
.map(|body| Self::Loop(body.to_box())))
|
.or(lx("loop")
|
||||||
.labelled("loop instruction")
|
.ignore_then(instr.clone())
|
||||||
.or(ShortDef::parser(expr.clone())
|
.map(|body| Self::Loop(body.to_box()))
|
||||||
.map(Self::Short)
|
.labelled("loop instruction"))
|
||||||
.labelled("shortcut instruction"))
|
.or(ShortDef::parser(expr.clone())
|
||||||
.or(FunDef::parser_def(instr, expr.clone())
|
.then_ignore(lx(";"))
|
||||||
.map(|(name, fun)| Self::FnDef(name, fun))
|
.map(Self::Short)
|
||||||
.labelled("function definition"))
|
.labelled("shortcut instruction"))
|
||||||
.or(id()
|
.or(FunDef::parser_def(instr, expr.clone())
|
||||||
.then_ignore(lx("="))
|
.map(|(name, fun)| Self::FnDef(name, fun))
|
||||||
.then(expr.clone())
|
.labelled("function definition"))
|
||||||
.map(|(id, ex)| Self::Assign(id, ex))
|
.or(id()
|
||||||
.labelled("variable assigniation."))
|
.then_ignore(lx("="))
|
||||||
.or(expr.map(Self::Expr))
|
.then(expr.clone())
|
||||||
|
.then_ignore(lx(";"))
|
||||||
|
.map(|(id, ex)| Self::Assign(id, ex))
|
||||||
|
.labelled("variable assigniation"))
|
||||||
|
.or(expr.then_ignore(lx(";")).map(Self::Expr))
|
||||||
})
|
})
|
||||||
.labelled("instruction")
|
.labelled("instruction")
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ impl Instr {
|
||||||
Self::Expr(expr) => no_short(expr.eval(context)?),
|
Self::Expr(expr) => no_short(expr.eval(context)?),
|
||||||
Self::Init(name, expr) => {
|
Self::Init(name, expr) => {
|
||||||
let value = expr.eval(context)?;
|
let value = expr.eval(context)?;
|
||||||
context.scope().borrow_mut().append(name.clone(), value);
|
context.scope().borrow_mut().define(name.clone(), value);
|
||||||
no_short(())
|
no_short(())
|
||||||
}
|
}
|
||||||
Self::Assign(name, expr) => {
|
Self::Assign(name, expr) => {
|
||||||
|
@ -262,7 +262,7 @@ impl Expr {
|
||||||
.map(|(e, a)| Self::Access(e.to_box(), a)))
|
.map(|(e, a)| Self::Access(e.to_box(), a)))
|
||||||
.or((left.clone())
|
.or((left.clone())
|
||||||
.then_ignore(lx("("))
|
.then_ignore(lx("("))
|
||||||
.then(expr.clone().then_ignore(lx(",")).repeated())
|
.then(expr.clone().separated_by(lx(",")))
|
||||||
.then_ignore(lx(")"))
|
.then_ignore(lx(")"))
|
||||||
.map(|(e, a)| Self::Call(e.to_box(), a)))
|
.map(|(e, a)| Self::Call(e.to_box(), a)))
|
||||||
.or((left.clone())
|
.or((left.clone())
|
||||||
|
@ -354,6 +354,21 @@ impl Op {
|
||||||
Ok(match (self, l, r) {
|
Ok(match (self, l, r) {
|
||||||
(Self::Add, Value::Str(l), Value::Str(r)) => Value::Str(format!("{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::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)?,
|
_ => Err(EvalError::WrongType)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -400,6 +415,7 @@ impl Litteral {
|
||||||
.ignore_then(char.repeated())
|
.ignore_then(char.repeated())
|
||||||
.then_ignore(just("\""))
|
.then_ignore(just("\""))
|
||||||
.map(|s| Self::Str(s.iter().collect())))
|
.map(|s| Self::Str(s.iter().collect())))
|
||||||
|
.or(just("none").map(|_| Self::None))
|
||||||
.or(just("true")
|
.or(just("true")
|
||||||
.map(|_| true)
|
.map(|_| true)
|
||||||
.or(just("false").map(|_| false))
|
.or(just("false").map(|_| false))
|
||||||
|
|
17
src/lib.rs
17
src/lib.rs
|
@ -53,6 +53,19 @@ impl Context {
|
||||||
Ok((parsed, value))
|
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>> {
|
pub fn scope(&self) -> Rc<RefCell<Scope>> {
|
||||||
self.frame.clone()
|
self.frame.clone()
|
||||||
}
|
}
|
||||||
|
@ -88,7 +101,7 @@ impl Scope {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append(&mut self, name: String, value: Value) {
|
pub fn define(&mut self, name: String, value: Value) {
|
||||||
self.defs.insert(name, value);
|
self.defs.insert(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +222,7 @@ impl Function {
|
||||||
FunImpl::Def(def) => Scope::alt(context, self.capturing.clone(), |context| {
|
FunImpl::Def(def) => Scope::alt(context, self.capturing.clone(), |context| {
|
||||||
let names = def.args.iter().cloned();
|
let names = def.args.iter().cloned();
|
||||||
for (name, value) in names.zip(args.into_iter().chain(repeat(Value::None))) {
|
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) {
|
match def.body.eval(context) {
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue