Removed ident type, fixed tests
This commit is contained in:
parent
ce2de21d9b
commit
176467dfc8
|
@ -50,62 +50,38 @@ impl<T: Hash> Hash for Spanned<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Ident {
|
|
||||||
pub ident: String,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ident {
|
|
||||||
pub fn new(ident: String, span: Span) -> Self {
|
|
||||||
Self { ident, span }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Ident {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.ident == other.ident
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for Ident {
|
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.ident.hash(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Hash)]
|
#[derive(Debug, PartialEq, Clone, Hash)]
|
||||||
pub struct Assignable {
|
pub struct Assignable {
|
||||||
pub ident: Ident,
|
pub ident: Spanned<String>,
|
||||||
pub kind: AssignableKind,
|
pub kind: AssignableKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Hash)]
|
#[derive(Debug, PartialEq, Clone, Hash)]
|
||||||
pub enum AssignableKind {
|
pub enum AssignableKind {
|
||||||
Variable,
|
Variable,
|
||||||
Index { indices: Vec<Spanned<ExprKind>> },
|
Index { indices: Vec<Spanned<Expr>> },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InvalidAssignable;
|
pub struct InvalidAssignable;
|
||||||
|
|
||||||
impl Assignable {
|
impl Assignable {
|
||||||
pub fn from_expr(expr: Spanned<ExprKind>) -> Result<Assignable, InvalidAssignable> {
|
pub fn from_expr(expr: Spanned<Expr>) -> Result<Assignable, InvalidAssignable> {
|
||||||
match expr.item {
|
match expr.item {
|
||||||
ExprKind::Variable(ident) => Ok(Assignable {
|
Expr::Variable(ident) => Ok(Assignable {
|
||||||
ident: Ident::new(ident, expr.span),
|
ident: Spanned::new(ident, expr.span),
|
||||||
kind: AssignableKind::Variable,
|
kind: AssignableKind::Variable,
|
||||||
}),
|
}),
|
||||||
ExprKind::Index { expr, index } => Self::from_index(*expr, *index),
|
Expr::Index { expr, index } => Self::from_index(*expr, *index),
|
||||||
_ => Err(InvalidAssignable),
|
_ => Err(InvalidAssignable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_index(mut buf: Spanned<ExprKind>, index: Spanned<ExprKind>) -> Result<Assignable, InvalidAssignable> {
|
fn from_index(mut buf: Spanned<Expr>, index: Spanned<Expr>) -> Result<Assignable, InvalidAssignable> {
|
||||||
let mut indices = vec![index];
|
let mut indices = vec![index];
|
||||||
let ident = loop {
|
let ident = loop {
|
||||||
match buf.item {
|
match buf.item {
|
||||||
ExprKind::Variable(ident) => break ident,
|
Expr::Variable(ident) => break ident,
|
||||||
ExprKind::Index { expr, index } => {
|
Expr::Index { expr, index } => {
|
||||||
indices.push(*index);
|
indices.push(*index);
|
||||||
buf = *expr;
|
buf = *expr;
|
||||||
}
|
}
|
||||||
|
@ -115,23 +91,20 @@ impl Assignable {
|
||||||
|
|
||||||
indices.reverse();
|
indices.reverse();
|
||||||
Ok(Assignable {
|
Ok(Assignable {
|
||||||
ident: Ident::new(ident, buf.span),
|
ident: Spanned::new(ident, buf.span),
|
||||||
kind: AssignableKind::Index { indices },
|
kind: AssignableKind::Index { indices },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Hash)]
|
pub type Block = Vec<Spanned<Stmt>>;
|
||||||
pub struct Block {
|
|
||||||
pub block: Vec<Spanned<StmtKind>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A syntactic unit expressing an effect.
|
/// A syntactic unit expressing an effect.
|
||||||
#[derive(Debug, PartialEq, Clone, Hash)]
|
#[derive(Debug, PartialEq, Clone, Hash)]
|
||||||
pub enum StmtKind {
|
pub enum Stmt {
|
||||||
// Control flow
|
// Control flow
|
||||||
If {
|
If {
|
||||||
cond: Spanned<ExprKind>,
|
cond: Spanned<Expr>,
|
||||||
body: Block,
|
body: Block,
|
||||||
},
|
},
|
||||||
Loop {
|
Loop {
|
||||||
|
@ -141,31 +114,31 @@ pub enum StmtKind {
|
||||||
HopBack,
|
HopBack,
|
||||||
|
|
||||||
Var {
|
Var {
|
||||||
ident: Ident,
|
ident: Spanned<String>,
|
||||||
init: Option<Spanned<ExprKind>>,
|
init: Option<Spanned<Expr>>,
|
||||||
},
|
},
|
||||||
Assign {
|
Assign {
|
||||||
assignable: Assignable,
|
assignable: Assignable,
|
||||||
value: Spanned<ExprKind>,
|
value: Spanned<Expr>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Functio {
|
Functio {
|
||||||
ident: Ident,
|
ident: Spanned<String>,
|
||||||
params: Vec<Ident>,
|
params: Vec<Spanned<String>>,
|
||||||
body: Block,
|
body: Block,
|
||||||
},
|
},
|
||||||
BfFunctio {
|
BfFunctio {
|
||||||
ident: Ident,
|
ident: Spanned<String>,
|
||||||
tape_len: Option<Spanned<ExprKind>>,
|
tape_len: Option<Spanned<Expr>>,
|
||||||
code: Vec<u8>,
|
code: Vec<u8>,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
expr: Spanned<ExprKind>,
|
expr: Spanned<Expr>,
|
||||||
args: Vec<Spanned<ExprKind>>,
|
args: Vec<Spanned<Expr>>,
|
||||||
},
|
},
|
||||||
Print(Spanned<ExprKind>),
|
Print(Spanned<Expr>),
|
||||||
Read(Assignable),
|
Read(Assignable),
|
||||||
Melo(Ident),
|
Melo(Spanned<String>),
|
||||||
Rlyeh,
|
Rlyeh,
|
||||||
Rickroll,
|
Rickroll,
|
||||||
}
|
}
|
||||||
|
@ -173,20 +146,20 @@ pub enum StmtKind {
|
||||||
/// Expression is parse unit which do not cause any effect,
|
/// Expression is parse unit which do not cause any effect,
|
||||||
/// like math and logical operations or values.
|
/// like math and logical operations or values.
|
||||||
#[derive(Debug, PartialEq, Clone, Hash)]
|
#[derive(Debug, PartialEq, Clone, Hash)]
|
||||||
pub enum ExprKind {
|
pub enum Expr {
|
||||||
BinOp {
|
BinOp {
|
||||||
lhs: Box<Spanned<ExprKind>>,
|
lhs: Box<Spanned<Expr>>,
|
||||||
rhs: Box<Spanned<ExprKind>>,
|
rhs: Box<Spanned<Expr>>,
|
||||||
kind: BinOpKind,
|
kind: BinOpKind,
|
||||||
},
|
},
|
||||||
Not(Box<Spanned<ExprKind>>),
|
Not(Box<Spanned<Expr>>),
|
||||||
Literal(Value),
|
Literal(Value),
|
||||||
Cart(Vec<(Spanned<ExprKind>, Spanned<ExprKind>)>),
|
Cart(Vec<(Spanned<Expr>, Spanned<Expr>)>),
|
||||||
Index {
|
Index {
|
||||||
expr: Box<Spanned<ExprKind>>,
|
expr: Box<Spanned<Expr>>,
|
||||||
index: Box<Spanned<ExprKind>>,
|
index: Box<Spanned<Expr>>,
|
||||||
},
|
},
|
||||||
Len(Box<Spanned<ExprKind>>),
|
Len(Box<Spanned<Expr>>),
|
||||||
Variable(String),
|
Variable(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ use std::{
|
||||||
use rand::random;
|
use rand::random;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{Assignable, AssignableKind, ExprKind, Ident, Spanned, StmtKind},
|
ast::{Assignable, AssignableKind, Expr, Spanned, Stmt},
|
||||||
base_55,
|
base_55,
|
||||||
consts::ablescript_consts,
|
consts::ablescript_consts,
|
||||||
error::{Error, ErrorKind},
|
error::{Error, ErrorKind},
|
||||||
|
@ -108,7 +108,7 @@ impl ExecEnv {
|
||||||
/// Execute a set of Statements in the root stack frame. Return an
|
/// Execute a set of Statements in the root stack frame. Return an
|
||||||
/// error if one or more of the Stmts failed to evaluate, or if a
|
/// error if one or more of the Stmts failed to evaluate, or if a
|
||||||
/// `break` or `hopback` statement occurred at the top level.
|
/// `break` or `hopback` statement occurred at the top level.
|
||||||
pub fn eval_stmts(&mut self, stmts: &[Spanned<StmtKind>]) -> Result<(), Error> {
|
pub fn eval_stmts(&mut self, stmts: &[Spanned<Stmt>]) -> Result<(), Error> {
|
||||||
match self.eval_stmts_hs(stmts, false)? {
|
match self.eval_stmts_hs(stmts, false)? {
|
||||||
HaltStatus::Finished => Ok(()),
|
HaltStatus::Finished => Ok(()),
|
||||||
HaltStatus::Break(span) | HaltStatus::Hopback(span) => Err(Error {
|
HaltStatus::Break(span) | HaltStatus::Hopback(span) => Err(Error {
|
||||||
|
@ -128,7 +128,7 @@ impl ExecEnv {
|
||||||
/// function over `eval_stmts`.
|
/// function over `eval_stmts`.
|
||||||
fn eval_stmts_hs(
|
fn eval_stmts_hs(
|
||||||
&mut self,
|
&mut self,
|
||||||
stmts: &[Spanned<StmtKind>],
|
stmts: &[Spanned<Stmt>],
|
||||||
stackframe: bool,
|
stackframe: bool,
|
||||||
) -> Result<HaltStatus, Error> {
|
) -> Result<HaltStatus, Error> {
|
||||||
let init_depth = self.stack.len();
|
let init_depth = self.stack.len();
|
||||||
|
@ -155,9 +155,9 @@ impl ExecEnv {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate an Expr, returning its value or an error.
|
/// Evaluate an Expr, returning its value or an error.
|
||||||
fn eval_expr(&self, expr: &Spanned<ExprKind>) -> Result<Value, Error> {
|
fn eval_expr(&self, expr: &Spanned<Expr>) -> Result<Value, Error> {
|
||||||
use crate::ast::BinOpKind::*;
|
use crate::ast::BinOpKind::*;
|
||||||
use crate::ast::ExprKind::*;
|
use crate::ast::Expr::*;
|
||||||
|
|
||||||
Ok(match &expr.item {
|
Ok(match &expr.item {
|
||||||
BinOp { lhs, rhs, kind } => {
|
BinOp { lhs, rhs, kind } => {
|
||||||
|
@ -176,7 +176,7 @@ impl ExecEnv {
|
||||||
}
|
}
|
||||||
Not(expr) => !self.eval_expr(expr)?,
|
Not(expr) => !self.eval_expr(expr)?,
|
||||||
Literal(value) => value.clone(),
|
Literal(value) => value.clone(),
|
||||||
ExprKind::Cart(members) => Value::Cart(
|
Expr::Cart(members) => Value::Cart(
|
||||||
members
|
members
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(value, key)| {
|
.map(|(value, key)| {
|
||||||
|
@ -200,47 +200,44 @@ impl ExecEnv {
|
||||||
|
|
||||||
// TODO: not too happy with constructing an artificial
|
// TODO: not too happy with constructing an artificial
|
||||||
// Ident here.
|
// Ident here.
|
||||||
Variable(name) => self.get_var(&Ident {
|
Variable(name) => self.get_var(&Spanned::new(name.to_owned(), expr.span.clone()))?,
|
||||||
ident: name.to_owned(),
|
|
||||||
span: expr.span.clone(),
|
|
||||||
})?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the action indicated by a statement.
|
/// Perform the action indicated by a statement.
|
||||||
fn eval_stmt(&mut self, stmt: &Spanned<StmtKind>) -> Result<HaltStatus, Error> {
|
fn eval_stmt(&mut self, stmt: &Spanned<Stmt>) -> Result<HaltStatus, Error> {
|
||||||
match &stmt.item {
|
match &stmt.item {
|
||||||
StmtKind::Print(expr) => {
|
Stmt::Print(expr) => {
|
||||||
println!("{}", self.eval_expr(expr)?);
|
println!("{}", self.eval_expr(expr)?);
|
||||||
}
|
}
|
||||||
StmtKind::Var { ident, init } => {
|
Stmt::Var { ident, init } => {
|
||||||
let init = match init {
|
let init = match init {
|
||||||
Some(e) => self.eval_expr(e)?,
|
Some(e) => self.eval_expr(e)?,
|
||||||
None => Value::Nul,
|
None => Value::Nul,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.decl_var(&ident.ident, init);
|
self.decl_var(&ident.item, init);
|
||||||
}
|
}
|
||||||
StmtKind::Functio {
|
Stmt::Functio {
|
||||||
ident,
|
ident,
|
||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
} => {
|
} => {
|
||||||
self.decl_var(
|
self.decl_var(
|
||||||
&ident.ident,
|
&ident.item,
|
||||||
Value::Functio(Functio::Able {
|
Value::Functio(Functio::Able {
|
||||||
params: params.iter().map(|ident| ident.ident.to_owned()).collect(),
|
params: params.iter().map(|ident| ident.item.to_owned()).collect(),
|
||||||
body: body.block.to_owned(),
|
body: body.to_owned(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
StmtKind::BfFunctio {
|
Stmt::BfFunctio {
|
||||||
ident,
|
ident,
|
||||||
tape_len,
|
tape_len,
|
||||||
code,
|
code,
|
||||||
} => {
|
} => {
|
||||||
self.decl_var(
|
self.decl_var(
|
||||||
&ident.ident,
|
&ident.item,
|
||||||
Value::Functio(Functio::Bf {
|
Value::Functio(Functio::Bf {
|
||||||
instructions: code.to_owned(),
|
instructions: code.to_owned(),
|
||||||
tape_len: tape_len
|
tape_len: tape_len
|
||||||
|
@ -252,47 +249,47 @@ impl ExecEnv {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
StmtKind::If { cond, body } => {
|
Stmt::If { cond, body } => {
|
||||||
if self.eval_expr(cond)?.into_abool().to_bool() {
|
if self.eval_expr(cond)?.into_abool().to_bool() {
|
||||||
return self.eval_stmts_hs(&body.block, true);
|
return self.eval_stmts_hs(body, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Call { expr, args } => {
|
Stmt::Call { expr, args } => {
|
||||||
let func = self.eval_expr(expr)?.into_functio();
|
let func = self.eval_expr(expr)?.into_functio();
|
||||||
|
|
||||||
self.fn_call(func, args, &stmt.span)?;
|
self.fn_call(func, args, &stmt.span)?;
|
||||||
}
|
}
|
||||||
StmtKind::Loop { body } => loop {
|
Stmt::Loop { body } => loop {
|
||||||
let res = self.eval_stmts_hs(&body.block, true)?;
|
let res = self.eval_stmts_hs(body, true)?;
|
||||||
match res {
|
match res {
|
||||||
HaltStatus::Finished => {}
|
HaltStatus::Finished => {}
|
||||||
HaltStatus::Break(_) => break,
|
HaltStatus::Break(_) => break,
|
||||||
HaltStatus::Hopback(_) => continue,
|
HaltStatus::Hopback(_) => continue,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
StmtKind::Assign { assignable, value } => {
|
Stmt::Assign { assignable, value } => {
|
||||||
self.assign(assignable, self.eval_expr(value)?)?;
|
self.assign(assignable, self.eval_expr(value)?)?;
|
||||||
}
|
}
|
||||||
StmtKind::Break => {
|
Stmt::Break => {
|
||||||
return Ok(HaltStatus::Break(stmt.span.clone()));
|
return Ok(HaltStatus::Break(stmt.span.clone()));
|
||||||
}
|
}
|
||||||
StmtKind::HopBack => {
|
Stmt::HopBack => {
|
||||||
return Ok(HaltStatus::Hopback(stmt.span.clone()));
|
return Ok(HaltStatus::Hopback(stmt.span.clone()));
|
||||||
}
|
}
|
||||||
StmtKind::Melo(ident) => {
|
Stmt::Melo(ident) => {
|
||||||
self.get_var_mut(ident)?.melo = true;
|
self.get_var_mut(ident)?.melo = true;
|
||||||
}
|
}
|
||||||
StmtKind::Rlyeh => {
|
Stmt::Rlyeh => {
|
||||||
// Maybe print a creepy error message or something
|
// Maybe print a creepy error message or something
|
||||||
// here at some point. ~~Alex
|
// here at some point. ~~Alex
|
||||||
exit(random());
|
exit(random());
|
||||||
}
|
}
|
||||||
StmtKind::Rickroll => {
|
Stmt::Rickroll => {
|
||||||
stdout()
|
stdout()
|
||||||
.write_all(include_str!("rickroll").as_bytes())
|
.write_all(include_str!("rickroll").as_bytes())
|
||||||
.expect("Failed to write to stdout");
|
.expect("Failed to write to stdout");
|
||||||
}
|
}
|
||||||
StmtKind::Read(assignable) => {
|
Stmt::Read(assignable) => {
|
||||||
let mut value = 0;
|
let mut value = 0;
|
||||||
for _ in 0..READ_BITS {
|
for _ in 0..READ_BITS {
|
||||||
value <<= 1;
|
value <<= 1;
|
||||||
|
@ -360,7 +357,7 @@ impl ExecEnv {
|
||||||
fn fn_call(
|
fn fn_call(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: Functio,
|
func: Functio,
|
||||||
args: &[Spanned<ExprKind>],
|
args: &[Spanned<Expr>],
|
||||||
span: &Range<usize>,
|
span: &Range<usize>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Arguments that are ExprKind::Variable are pass by
|
// Arguments that are ExprKind::Variable are pass by
|
||||||
|
@ -368,11 +365,8 @@ impl ExecEnv {
|
||||||
let args = args
|
let args = args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| {
|
.map(|arg| {
|
||||||
if let ExprKind::Variable(name) = &arg.item {
|
if let Expr::Variable(name) = &arg.item {
|
||||||
self.get_var_rc(&Ident {
|
self.get_var_rc(&Spanned::new(name.to_owned(), arg.span.clone()))
|
||||||
ident: name.to_owned(),
|
|
||||||
span: arg.span.clone(),
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
self.eval_expr(arg).map(ValueRef::new)
|
self.eval_expr(arg).map(ValueRef::new)
|
||||||
}
|
}
|
||||||
|
@ -522,9 +516,9 @@ impl ExecEnv {
|
||||||
|
|
||||||
/// Get the value of a variable. Throw an error if the variable is
|
/// Get the value of a variable. Throw an error if the variable is
|
||||||
/// inaccessible or banned.
|
/// inaccessible or banned.
|
||||||
fn get_var(&self, name: &Ident) -> Result<Value, Error> {
|
fn get_var(&self, name: &Spanned<String>) -> Result<Value, Error> {
|
||||||
// One-letter names are reserved as base55 numbers.
|
// One-letter names are reserved as base55 numbers.
|
||||||
let mut chars = name.ident.chars();
|
let mut chars = name.item.chars();
|
||||||
if let (Some(first), None) = (chars.next(), chars.next()) {
|
if let (Some(first), None) = (chars.next(), chars.next()) {
|
||||||
return Ok(Value::Int(base_55::char2num(first)));
|
return Ok(Value::Int(base_55::char2num(first)));
|
||||||
}
|
}
|
||||||
|
@ -535,20 +529,20 @@ impl ExecEnv {
|
||||||
.stack
|
.stack
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find_map(|scope| scope.variables.get(&name.ident))
|
.find_map(|scope| scope.variables.get(&name.item))
|
||||||
{
|
{
|
||||||
Some(var) => {
|
Some(var) => {
|
||||||
if !var.melo {
|
if !var.melo {
|
||||||
Ok(var.value.borrow().clone())
|
Ok(var.value.borrow().clone())
|
||||||
} else {
|
} else {
|
||||||
Err(Error {
|
Err(Error {
|
||||||
kind: ErrorKind::MeloVariable(name.ident.to_owned()),
|
kind: ErrorKind::MeloVariable(name.item.to_owned()),
|
||||||
span: name.span.clone(),
|
span: name.span.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => Err(Error {
|
None => Err(Error {
|
||||||
kind: ErrorKind::UnknownVariable(name.ident.to_owned()),
|
kind: ErrorKind::UnknownVariable(name.item.to_owned()),
|
||||||
span: name.span.clone(),
|
span: name.span.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -556,27 +550,27 @@ impl ExecEnv {
|
||||||
|
|
||||||
/// Get a mutable reference to a variable. Throw an error if the
|
/// Get a mutable reference to a variable. Throw an error if the
|
||||||
/// variable is inaccessible or banned.
|
/// variable is inaccessible or banned.
|
||||||
fn get_var_mut(&mut self, name: &Ident) -> Result<&mut Variable, Error> {
|
fn get_var_mut(&mut self, name: &Spanned<String>) -> Result<&mut Variable, Error> {
|
||||||
// This function has a lot of duplicated code with `get_var`,
|
// This function has a lot of duplicated code with `get_var`,
|
||||||
// which I feel like is a bad sign...
|
// which I feel like is a bad sign...
|
||||||
match self
|
match self
|
||||||
.stack
|
.stack
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.rev()
|
.rev()
|
||||||
.find_map(|scope| scope.variables.get_mut(&name.ident))
|
.find_map(|scope| scope.variables.get_mut(&name.item))
|
||||||
{
|
{
|
||||||
Some(var) => {
|
Some(var) => {
|
||||||
if !var.melo {
|
if !var.melo {
|
||||||
Ok(var)
|
Ok(var)
|
||||||
} else {
|
} else {
|
||||||
Err(Error {
|
Err(Error {
|
||||||
kind: ErrorKind::MeloVariable(name.ident.to_owned()),
|
kind: ErrorKind::MeloVariable(name.item.to_owned()),
|
||||||
span: name.span.clone(),
|
span: name.span.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => Err(Error {
|
None => Err(Error {
|
||||||
kind: ErrorKind::UnknownVariable(name.ident.to_owned()),
|
kind: ErrorKind::UnknownVariable(name.item.to_owned()),
|
||||||
span: name.span.clone(),
|
span: name.span.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -584,7 +578,7 @@ impl ExecEnv {
|
||||||
|
|
||||||
/// Get an Rc'd pointer to the value of a variable. Throw an error
|
/// Get an Rc'd pointer to the value of a variable. Throw an error
|
||||||
/// if the variable is inaccessible or banned.
|
/// if the variable is inaccessible or banned.
|
||||||
fn get_var_rc(&mut self, name: &Ident) -> Result<ValueRef, Error> {
|
fn get_var_rc(&mut self, name: &Spanned<String>) -> Result<ValueRef, Error> {
|
||||||
Ok(self.get_var_mut(name)?.value.clone())
|
Ok(self.get_var_mut(name)?.value.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,7 +600,7 @@ impl ExecEnv {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::ast::ExprKind;
|
use crate::ast::Expr;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -615,14 +609,14 @@ mod tests {
|
||||||
// Check that 2 + 2 = 4.
|
// Check that 2 + 2 = 4.
|
||||||
let env = ExecEnv::new();
|
let env = ExecEnv::new();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.eval_expr(&Expr {
|
env.eval_expr(&Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(2)),
|
item: Expr::Literal(Value::Int(2)),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(2)),
|
item: Expr::Literal(Value::Int(2)),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
}),
|
}),
|
||||||
kind: crate::ast::BinOpKind::Add,
|
kind: crate::ast::BinOpKind::Add,
|
||||||
|
@ -642,14 +636,14 @@ mod tests {
|
||||||
|
|
||||||
let env = ExecEnv::new();
|
let env = ExecEnv::new();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.eval_expr(&Expr {
|
env.eval_expr(&Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(2)),
|
item: Expr::Literal(Value::Int(2)),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Abool(Abool::Always)),
|
item: Expr::Literal(Value::Abool(Abool::Always)),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
}),
|
}),
|
||||||
kind: crate::ast::BinOpKind::Add,
|
kind: crate::ast::BinOpKind::Add,
|
||||||
|
@ -667,14 +661,14 @@ mod tests {
|
||||||
// of panicking.
|
// of panicking.
|
||||||
let env = ExecEnv::new();
|
let env = ExecEnv::new();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.eval_expr(&Expr {
|
env.eval_expr(&Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(isize::MAX)),
|
item: Expr::Literal(Value::Int(isize::MAX)),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(1)),
|
item: Expr::Literal(Value::Int(1)),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
}),
|
}),
|
||||||
kind: crate::ast::BinOpKind::Add,
|
kind: crate::ast::BinOpKind::Add,
|
||||||
|
@ -687,14 +681,14 @@ mod tests {
|
||||||
|
|
||||||
// And the same for divide by zero.
|
// And the same for divide by zero.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.eval_expr(&Expr {
|
env.eval_expr(&Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(84)),
|
item: Expr::Literal(Value::Int(84)),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(0)),
|
item: Expr::Literal(Value::Int(0)),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
}),
|
}),
|
||||||
kind: crate::ast::BinOpKind::Divide,
|
kind: crate::ast::BinOpKind::Divide,
|
||||||
|
@ -728,8 +722,8 @@ mod tests {
|
||||||
// Declaring and reading from a variable.
|
// Declaring and reading from a variable.
|
||||||
eval(&mut env, "var foo = 32; var bar = foo + 1;").unwrap();
|
eval(&mut env, "var foo = 32; var bar = foo + 1;").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.get_var(&Ident {
|
env.get_var(&Spanned {
|
||||||
ident: "bar".to_owned(),
|
item: "bar".to_owned(),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -739,8 +733,8 @@ mod tests {
|
||||||
// Assigning an existing variable.
|
// Assigning an existing variable.
|
||||||
eval(&mut env, "foo = /*hi*/;").unwrap();
|
eval(&mut env, "foo = /*hi*/;").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.get_var(&Ident {
|
env.get_var(&Spanned {
|
||||||
ident: "foo".to_owned(),
|
item: "foo".to_owned(),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -765,8 +759,8 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.get_var(&Ident {
|
env.get_var(&Spanned {
|
||||||
ident: "foo".to_owned(),
|
item: "foo".to_owned(),
|
||||||
span: 1..1,
|
span: 1..1,
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
|
|
@ -29,7 +29,7 @@ impl<'source> Parser<'source> {
|
||||||
/// Start parsing tokens
|
/// Start parsing tokens
|
||||||
///
|
///
|
||||||
/// Loops trough lexer, parses statements, returns AST
|
/// Loops trough lexer, parses statements, returns AST
|
||||||
pub fn init(&mut self) -> Result<Vec<Spanned<StmtKind>>, Error> {
|
pub fn init(&mut self) -> Result<Block, Error> {
|
||||||
let mut ast = vec![];
|
let mut ast = vec![];
|
||||||
while let Some(token) = self.lexer.next() {
|
while let Some(token) = self.lexer.next() {
|
||||||
match token {
|
match token {
|
||||||
|
@ -37,7 +37,7 @@ impl<'source> Parser<'source> {
|
||||||
Token::Comment => continue,
|
Token::Comment => continue,
|
||||||
|
|
||||||
// T-Dark block (replace `lang` with `script`)
|
// T-Dark block (replace `lang` with `script`)
|
||||||
Token::TDark => ast.extend(self.tdark_flow()?.block),
|
Token::TDark => ast.extend(self.tdark_flow()?),
|
||||||
token => ast.push(self.parse(token)?),
|
token => ast.push(self.parse(token)?),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ impl<'source> Parser<'source> {
|
||||||
///
|
///
|
||||||
/// This function will route to corresponding flow functions
|
/// This function will route to corresponding flow functions
|
||||||
/// which may advance the lexer iterator
|
/// which may advance the lexer iterator
|
||||||
fn parse(&mut self, token: Token) -> Result<Spanned<StmtKind>, Error> {
|
fn parse(&mut self, token: Token) -> Result<Spanned<Stmt>, Error> {
|
||||||
let start = self.lexer.span().start;
|
let start = self.lexer.span().start;
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
|
@ -75,22 +75,28 @@ impl<'source> Parser<'source> {
|
||||||
)),
|
)),
|
||||||
Token::Bff => Ok(Spanned::new(self.bff_flow()?, start..self.lexer.span().end)),
|
Token::Bff => Ok(Spanned::new(self.bff_flow()?, start..self.lexer.span().end)),
|
||||||
Token::Var => Ok(Spanned::new(self.var_flow()?, start..self.lexer.span().end)),
|
Token::Var => Ok(Spanned::new(self.var_flow()?, start..self.lexer.span().end)),
|
||||||
Token::Melo => Ok(Spanned::new(self.melo_flow()?, start..self.lexer.span().end)),
|
Token::Melo => Ok(Spanned::new(
|
||||||
Token::Loop => Ok(Spanned::new(self.loop_flow()?, start..self.lexer.span().end)),
|
self.melo_flow()?,
|
||||||
|
start..self.lexer.span().end,
|
||||||
|
)),
|
||||||
|
Token::Loop => Ok(Spanned::new(
|
||||||
|
self.loop_flow()?,
|
||||||
|
start..self.lexer.span().end,
|
||||||
|
)),
|
||||||
Token::Break => Ok(Spanned::new(
|
Token::Break => Ok(Spanned::new(
|
||||||
self.semicolon_terminated(StmtKind::Break)?,
|
self.semicolon_terminated(Stmt::Break)?,
|
||||||
start..self.lexer.span().end,
|
start..self.lexer.span().end,
|
||||||
)),
|
)),
|
||||||
Token::HopBack => Ok(Spanned::new(
|
Token::HopBack => Ok(Spanned::new(
|
||||||
self.semicolon_terminated(StmtKind::HopBack)?,
|
self.semicolon_terminated(Stmt::HopBack)?,
|
||||||
start..self.lexer.span().end,
|
start..self.lexer.span().end,
|
||||||
)),
|
)),
|
||||||
Token::Rlyeh => Ok(Spanned::new(
|
Token::Rlyeh => Ok(Spanned::new(
|
||||||
self.semicolon_terminated(StmtKind::Rlyeh)?,
|
self.semicolon_terminated(Stmt::Rlyeh)?,
|
||||||
start..self.lexer.span().end,
|
start..self.lexer.span().end,
|
||||||
)),
|
)),
|
||||||
Token::Rickroll => Ok(Spanned::new(
|
Token::Rickroll => Ok(Spanned::new(
|
||||||
self.semicolon_terminated(StmtKind::Rickroll)?,
|
self.semicolon_terminated(Stmt::Rickroll)?,
|
||||||
start..self.lexer.span().end,
|
start..self.lexer.span().end,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
|
@ -114,7 +120,7 @@ impl<'source> Parser<'source> {
|
||||||
/// Require statement to be semicolon terminated
|
/// Require statement to be semicolon terminated
|
||||||
///
|
///
|
||||||
/// Utility function for short statements
|
/// Utility function for short statements
|
||||||
fn semicolon_terminated(&mut self, stmt_kind: StmtKind) -> Result<StmtKind, Error> {
|
fn semicolon_terminated(&mut self, stmt_kind: Stmt) -> Result<Stmt, Error> {
|
||||||
self.require(Token::Semicolon)?;
|
self.require(Token::Semicolon)?;
|
||||||
Ok(stmt_kind)
|
Ok(stmt_kind)
|
||||||
}
|
}
|
||||||
|
@ -128,16 +134,16 @@ impl<'source> Parser<'source> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an Identifier
|
/// Get an Identifier
|
||||||
fn get_ident(&mut self) -> Result<Ident, Error> {
|
fn get_ident(&mut self) -> Result<Spanned<String>, Error> {
|
||||||
match self.checked_next()? {
|
match self.checked_next()? {
|
||||||
Token::Identifier(ident) => Ok(Ident {
|
Token::Identifier(ident) => Ok(Spanned::new(
|
||||||
ident: if self.tdark {
|
if self.tdark {
|
||||||
ident.replace("lang", "script")
|
ident.replace("lang", "script")
|
||||||
} else {
|
} else {
|
||||||
ident
|
ident
|
||||||
},
|
},
|
||||||
span: self.lexer.span(),
|
self.lexer.span(),
|
||||||
}),
|
)),
|
||||||
t => Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())),
|
t => Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +153,11 @@ impl<'source> Parser<'source> {
|
||||||
/// AbleScript strongly separates expressions from statements.
|
/// AbleScript strongly separates expressions from statements.
|
||||||
/// Expressions do not have any side effects and the are
|
/// Expressions do not have any side effects and the are
|
||||||
/// only mathematial and logical operations or values.
|
/// only mathematial and logical operations or values.
|
||||||
fn parse_expr(&mut self, token: Token, buf: &mut Option<Spanned<ExprKind>>) -> Result<Spanned<ExprKind>, Error> {
|
fn parse_expr(
|
||||||
|
&mut self,
|
||||||
|
token: Token,
|
||||||
|
buf: &mut Option<Spanned<Expr>>,
|
||||||
|
) -> Result<Spanned<Expr>, Error> {
|
||||||
let start = match buf {
|
let start = match buf {
|
||||||
Some(e) => e.span.start,
|
Some(e) => e.span.start,
|
||||||
None => self.lexer.span().start,
|
None => self.lexer.span().start,
|
||||||
|
@ -156,7 +166,7 @@ impl<'source> Parser<'source> {
|
||||||
match token {
|
match token {
|
||||||
// Values
|
// Values
|
||||||
Token::Identifier(i) => Ok(Spanned::new(
|
Token::Identifier(i) => Ok(Spanned::new(
|
||||||
ExprKind::Variable(if self.tdark {
|
Expr::Variable(if self.tdark {
|
||||||
i.replace("lang", "script")
|
i.replace("lang", "script")
|
||||||
} else {
|
} else {
|
||||||
i
|
i
|
||||||
|
@ -164,11 +174,11 @@ impl<'source> Parser<'source> {
|
||||||
start..self.lexer.span().end,
|
start..self.lexer.span().end,
|
||||||
)),
|
)),
|
||||||
Token::Integer(i) => Ok(Spanned::new(
|
Token::Integer(i) => Ok(Spanned::new(
|
||||||
ExprKind::Literal(Value::Int(i)),
|
Expr::Literal(Value::Int(i)),
|
||||||
start..self.lexer.span().end,
|
start..self.lexer.span().end,
|
||||||
)),
|
)),
|
||||||
Token::String(s) => Ok(Spanned::new(
|
Token::String(s) => Ok(Spanned::new(
|
||||||
ExprKind::Literal(Value::Str(if self.tdark {
|
Expr::Literal(Value::Str(if self.tdark {
|
||||||
s.replace("lang", "script")
|
s.replace("lang", "script")
|
||||||
} else {
|
} else {
|
||||||
s
|
s
|
||||||
|
@ -181,7 +191,10 @@ impl<'source> Parser<'source> {
|
||||||
self.index_flow(buf)?,
|
self.index_flow(buf)?,
|
||||||
start..self.lexer.span().end,
|
start..self.lexer.span().end,
|
||||||
)),
|
)),
|
||||||
None => Ok(Spanned::new(self.cart_flow()?, start..self.lexer.span().end)),
|
None => Ok(Spanned::new(
|
||||||
|
self.cart_flow()?,
|
||||||
|
start..self.lexer.span().end,
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Operations
|
// Operations
|
||||||
|
@ -203,7 +216,7 @@ impl<'source> Parser<'source> {
|
||||||
Token::Not => Ok(Spanned::new(
|
Token::Not => Ok(Spanned::new(
|
||||||
{
|
{
|
||||||
let next = self.checked_next()?;
|
let next = self.checked_next()?;
|
||||||
ExprKind::Not(Box::new(self.parse_expr(next, buf)?))
|
Expr::Not(Box::new(self.parse_expr(next, buf)?))
|
||||||
},
|
},
|
||||||
start..self.lexer.span().end,
|
start..self.lexer.span().end,
|
||||||
)),
|
)),
|
||||||
|
@ -214,7 +227,7 @@ impl<'source> Parser<'source> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flow for creating carts
|
/// Flow for creating carts
|
||||||
fn cart_flow(&mut self) -> Result<ExprKind, Error> {
|
fn cart_flow(&mut self) -> Result<Expr, Error> {
|
||||||
let mut cart = vec![];
|
let mut cart = vec![];
|
||||||
let mut buf = None;
|
let mut buf = None;
|
||||||
|
|
||||||
|
@ -256,24 +269,24 @@ impl<'source> Parser<'source> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ExprKind::Cart(cart))
|
Ok(Expr::Cart(cart))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flow for indexing operations
|
/// Flow for indexing operations
|
||||||
///
|
///
|
||||||
/// Indexing with empty index resolves to length of expression, else it indexes
|
/// Indexing with empty index resolves to length of expression, else it indexes
|
||||||
fn index_flow(&mut self, expr: Spanned<ExprKind>) -> Result<ExprKind, Error> {
|
fn index_flow(&mut self, expr: Spanned<Expr>) -> Result<Expr, Error> {
|
||||||
let mut buf = None;
|
let mut buf = None;
|
||||||
Ok(loop {
|
Ok(loop {
|
||||||
match self.checked_next()? {
|
match self.checked_next()? {
|
||||||
Token::RightBracket => match buf {
|
Token::RightBracket => match buf {
|
||||||
Some(index) => {
|
Some(index) => {
|
||||||
break ExprKind::Index {
|
break Expr::Index {
|
||||||
expr: Box::new(expr),
|
expr: Box::new(expr),
|
||||||
index: Box::new(index),
|
index: Box::new(index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => break ExprKind::Len(Box::new(expr)),
|
None => break Expr::Len(Box::new(expr)),
|
||||||
},
|
},
|
||||||
token => buf = Some(self.parse_expr(token, &mut buf)?),
|
token => buf = Some(self.parse_expr(token, &mut buf)?),
|
||||||
}
|
}
|
||||||
|
@ -285,8 +298,12 @@ impl<'source> Parser<'source> {
|
||||||
/// Generates operation from LHS buffer and next expression as RHS
|
/// Generates operation from LHS buffer and next expression as RHS
|
||||||
///
|
///
|
||||||
/// This is unaware of precedence, as AbleScript do not have it
|
/// This is unaware of precedence, as AbleScript do not have it
|
||||||
fn binop_flow(&mut self, kind: BinOpKind, lhs: &mut Option<Spanned<ExprKind>>) -> Result<ExprKind, Error> {
|
fn binop_flow(
|
||||||
Ok(ExprKind::BinOp {
|
&mut self,
|
||||||
|
kind: BinOpKind,
|
||||||
|
lhs: &mut Option<Spanned<Expr>>,
|
||||||
|
) -> Result<Expr, Error> {
|
||||||
|
Ok(Expr::BinOp {
|
||||||
lhs: Box::new(
|
lhs: Box::new(
|
||||||
lhs.take()
|
lhs.take()
|
||||||
.ok_or_else(|| Error::new(ErrorKind::MissingLhs, self.lexer.span()))?,
|
.ok_or_else(|| Error::new(ErrorKind::MissingLhs, self.lexer.span()))?,
|
||||||
|
@ -303,7 +320,7 @@ impl<'source> Parser<'source> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse expressions until terminate token
|
/// Parse expressions until terminate token
|
||||||
fn expr_flow(&mut self, terminate: Token) -> Result<Spanned<ExprKind>, Error> {
|
fn expr_flow(&mut self, terminate: Token) -> Result<Spanned<Expr>, Error> {
|
||||||
let mut buf = None;
|
let mut buf = None;
|
||||||
Ok(loop {
|
Ok(loop {
|
||||||
match self.checked_next()? {
|
match self.checked_next()? {
|
||||||
|
@ -325,11 +342,11 @@ impl<'source> Parser<'source> {
|
||||||
loop {
|
loop {
|
||||||
match self.checked_next()? {
|
match self.checked_next()? {
|
||||||
Token::RightCurly => break,
|
Token::RightCurly => break,
|
||||||
Token::TDark => block.extend(self.tdark_flow()?.block),
|
Token::TDark => block.extend(self.tdark_flow()?),
|
||||||
t => block.push(self.parse(t)?),
|
t => block.push(self.parse(t)?),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Block { block })
|
Ok(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse T-Dark block
|
/// Parse T-Dark block
|
||||||
|
@ -343,13 +360,13 @@ impl<'source> Parser<'source> {
|
||||||
/// If Statement parser gets any kind of value (Identifier or Literal)
|
/// If Statement parser gets any kind of value (Identifier or Literal)
|
||||||
/// It cannot parse it as it do not parse expressions. Instead of it it
|
/// It cannot parse it as it do not parse expressions. Instead of it it
|
||||||
/// will parse it to function call or print statement.
|
/// will parse it to function call or print statement.
|
||||||
fn value_flow(&mut self, init: Token) -> Result<StmtKind, Error> {
|
fn value_flow(&mut self, init: Token) -> Result<Stmt, Error> {
|
||||||
let mut buf = Some(self.parse_expr(init, &mut None)?);
|
let mut buf = Some(self.parse_expr(init, &mut None)?);
|
||||||
let r = loop {
|
let r = loop {
|
||||||
match self.checked_next()? {
|
match self.checked_next()? {
|
||||||
// Print to stdout
|
// Print to stdout
|
||||||
Token::Print => {
|
Token::Print => {
|
||||||
let stmt = StmtKind::Print(buf.take().ok_or_else(|| {
|
let stmt = Stmt::Print(buf.take().ok_or_else(|| {
|
||||||
Error::new(ErrorKind::UnexpectedToken(Token::Print), self.lexer.span())
|
Error::new(ErrorKind::UnexpectedToken(Token::Print), self.lexer.span())
|
||||||
})?);
|
})?);
|
||||||
break self.semicolon_terminated(stmt)?;
|
break self.semicolon_terminated(stmt)?;
|
||||||
|
@ -368,7 +385,7 @@ impl<'source> Parser<'source> {
|
||||||
// Variable Assignment
|
// Variable Assignment
|
||||||
Token::Equal => {
|
Token::Equal => {
|
||||||
if let Some(Ok(assignable)) = buf.take().map(Assignable::from_expr) {
|
if let Some(Ok(assignable)) = buf.take().map(Assignable::from_expr) {
|
||||||
break StmtKind::Assign {
|
break Stmt::Assign {
|
||||||
assignable,
|
assignable,
|
||||||
value: self.expr_flow(Token::Semicolon)?,
|
value: self.expr_flow(Token::Semicolon)?,
|
||||||
};
|
};
|
||||||
|
@ -384,7 +401,7 @@ impl<'source> Parser<'source> {
|
||||||
Token::Read => {
|
Token::Read => {
|
||||||
if let Some(Ok(assignable)) = buf.take().map(Assignable::from_expr) {
|
if let Some(Ok(assignable)) = buf.take().map(Assignable::from_expr) {
|
||||||
self.require(Token::Semicolon)?;
|
self.require(Token::Semicolon)?;
|
||||||
break StmtKind::Read(assignable);
|
break Stmt::Read(assignable);
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
ErrorKind::UnexpectedToken(Token::Read),
|
ErrorKind::UnexpectedToken(Token::Read),
|
||||||
|
@ -403,20 +420,20 @@ impl<'source> Parser<'source> {
|
||||||
/// Parse If flow
|
/// Parse If flow
|
||||||
///
|
///
|
||||||
/// Consists of condition and block, there is no else
|
/// Consists of condition and block, there is no else
|
||||||
fn if_flow(&mut self) -> Result<StmtKind, Error> {
|
fn if_flow(&mut self) -> Result<Stmt, Error> {
|
||||||
self.require(Token::LeftParen)?;
|
self.require(Token::LeftParen)?;
|
||||||
|
|
||||||
let cond = self.expr_flow(Token::RightParen)?;
|
let cond = self.expr_flow(Token::RightParen)?;
|
||||||
|
|
||||||
let body = self.get_block()?;
|
let body = self.get_block()?;
|
||||||
|
|
||||||
Ok(StmtKind::If { cond, body })
|
Ok(Stmt::If { cond, body })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse functio flow
|
/// Parse functio flow
|
||||||
///
|
///
|
||||||
/// functio $ident (a, b, c) { ... }
|
/// functio $ident (a, b, c) { ... }
|
||||||
fn functio_flow(&mut self) -> Result<StmtKind, Error> {
|
fn functio_flow(&mut self) -> Result<Stmt, Error> {
|
||||||
let ident = self.get_ident()?;
|
let ident = self.get_ident()?;
|
||||||
|
|
||||||
self.require(Token::LeftParen)?;
|
self.require(Token::LeftParen)?;
|
||||||
|
@ -426,7 +443,7 @@ impl<'source> Parser<'source> {
|
||||||
match self.checked_next()? {
|
match self.checked_next()? {
|
||||||
Token::RightParen => break,
|
Token::RightParen => break,
|
||||||
Token::Identifier(i) => {
|
Token::Identifier(i) => {
|
||||||
params.push(Ident::new(i, self.lexer.span()));
|
params.push(Spanned::new(i, self.lexer.span()));
|
||||||
|
|
||||||
// Require comma (next) or right paren (end) after identifier
|
// Require comma (next) or right paren (end) after identifier
|
||||||
match self.checked_next()? {
|
match self.checked_next()? {
|
||||||
|
@ -446,7 +463,7 @@ impl<'source> Parser<'source> {
|
||||||
|
|
||||||
let body = self.get_block()?;
|
let body = self.get_block()?;
|
||||||
|
|
||||||
Ok(StmtKind::Functio {
|
Ok(Stmt::Functio {
|
||||||
ident,
|
ident,
|
||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
|
@ -456,7 +473,7 @@ impl<'source> Parser<'source> {
|
||||||
/// Parse BF function declaration
|
/// Parse BF function declaration
|
||||||
///
|
///
|
||||||
/// `bff $ident ([tapelen]) { ... }`
|
/// `bff $ident ([tapelen]) { ... }`
|
||||||
fn bff_flow(&mut self) -> Result<StmtKind, Error> {
|
fn bff_flow(&mut self) -> Result<Stmt, Error> {
|
||||||
let ident = self.get_ident()?;
|
let ident = self.get_ident()?;
|
||||||
|
|
||||||
let tape_len = match self.checked_next()? {
|
let tape_len = match self.checked_next()? {
|
||||||
|
@ -489,7 +506,7 @@ impl<'source> Parser<'source> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(StmtKind::BfFunctio {
|
Ok(Stmt::BfFunctio {
|
||||||
ident,
|
ident,
|
||||||
tape_len,
|
tape_len,
|
||||||
code,
|
code,
|
||||||
|
@ -497,7 +514,7 @@ impl<'source> Parser<'source> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse functio call flow
|
/// Parse functio call flow
|
||||||
fn functio_call_flow(&mut self, expr: Spanned<ExprKind>) -> Result<StmtKind, Error> {
|
fn functio_call_flow(&mut self, expr: Spanned<Expr>) -> Result<Stmt, Error> {
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
let mut buf = None;
|
let mut buf = None;
|
||||||
loop {
|
loop {
|
||||||
|
@ -526,11 +543,11 @@ impl<'source> Parser<'source> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.require(Token::Semicolon)?;
|
self.require(Token::Semicolon)?;
|
||||||
Ok(StmtKind::Call { expr, args })
|
Ok(Stmt::Call { expr, args })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse variable declaration
|
/// Parse variable declaration
|
||||||
fn var_flow(&mut self) -> Result<StmtKind, Error> {
|
fn var_flow(&mut self) -> Result<Stmt, Error> {
|
||||||
let ident = self.get_ident()?;
|
let ident = self.get_ident()?;
|
||||||
let init = match self.checked_next()? {
|
let init = match self.checked_next()? {
|
||||||
Token::Equal => Some(self.expr_flow(Token::Semicolon)?),
|
Token::Equal => Some(self.expr_flow(Token::Semicolon)?),
|
||||||
|
@ -538,20 +555,20 @@ impl<'source> Parser<'source> {
|
||||||
t => return Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())),
|
t => return Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(StmtKind::Var { ident, init })
|
Ok(Stmt::Var { ident, init })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse Melo flow
|
/// Parse Melo flow
|
||||||
fn melo_flow(&mut self) -> Result<StmtKind, Error> {
|
fn melo_flow(&mut self) -> Result<Stmt, Error> {
|
||||||
let ident = self.get_ident()?;
|
let ident = self.get_ident()?;
|
||||||
self.semicolon_terminated(StmtKind::Melo(ident))
|
self.semicolon_terminated(Stmt::Melo(ident))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse loop flow
|
/// Parse loop flow
|
||||||
///
|
///
|
||||||
/// `loop` is an infinite loop, no condition, only body
|
/// `loop` is an infinite loop, no condition, only body
|
||||||
fn loop_flow(&mut self) -> Result<StmtKind, Error> {
|
fn loop_flow(&mut self) -> Result<Stmt, Error> {
|
||||||
Ok(StmtKind::Loop {
|
Ok(Stmt::Loop {
|
||||||
body: self.get_block()?,
|
body: self.get_block()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -564,23 +581,23 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_math() {
|
fn simple_math() {
|
||||||
let code = "1 * (a + 3) / 666 print;";
|
let code = "1 * (a + 3) / 666 print;";
|
||||||
let expected = &[Stmt {
|
let expected = &[Spanned {
|
||||||
kind: StmtKind::Print(Expr {
|
item: Stmt::Print(Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(1)),
|
item: Expr::Literal(Value::Int(1)),
|
||||||
span: 0..1,
|
span: 0..1,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Variable("a".to_owned()),
|
item: Expr::Variable("a".to_owned()),
|
||||||
span: 5..6,
|
span: 5..6,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(3)),
|
item: Expr::Literal(Value::Int(3)),
|
||||||
span: 9..10,
|
span: 9..10,
|
||||||
}),
|
}),
|
||||||
kind: BinOpKind::Add,
|
kind: BinOpKind::Add,
|
||||||
|
@ -591,8 +608,8 @@ mod tests {
|
||||||
},
|
},
|
||||||
span: 0..11,
|
span: 0..11,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(666)),
|
item: Expr::Literal(Value::Int(666)),
|
||||||
span: 14..17,
|
span: 14..17,
|
||||||
}),
|
}),
|
||||||
kind: BinOpKind::Divide,
|
kind: BinOpKind::Divide,
|
||||||
|
@ -609,14 +626,14 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn variable_declaration() {
|
fn variable_declaration() {
|
||||||
let code = "var a = 42;";
|
let code = "var a = 42;";
|
||||||
let expected = &[Stmt {
|
let expected = &[Spanned {
|
||||||
kind: StmtKind::Var {
|
item: Stmt::Var {
|
||||||
ident: Ident {
|
ident: Spanned {
|
||||||
ident: "a".to_owned(),
|
item: "a".to_owned(),
|
||||||
span: 4..5,
|
span: 4..5,
|
||||||
},
|
},
|
||||||
init: Some(Expr {
|
init: Some(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(42)),
|
item: Expr::Literal(Value::Int(42)),
|
||||||
span: 8..10,
|
span: 8..10,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -630,31 +647,29 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn if_flow() {
|
fn if_flow() {
|
||||||
let code = "if (a == always) { /*Buy Able products!*/ print; }";
|
let code = "if (a == always) { /*Buy Able products!*/ print; }";
|
||||||
let expected = &[Stmt {
|
let expected = &[Spanned {
|
||||||
kind: StmtKind::If {
|
item: Stmt::If {
|
||||||
cond: Expr {
|
cond: Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Variable("a".to_owned()),
|
item: Expr::Variable("a".to_owned()),
|
||||||
span: 4..5,
|
span: 4..5,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Variable("always".to_owned()),
|
item: Expr::Variable("always".to_owned()),
|
||||||
span: 9..15,
|
span: 9..15,
|
||||||
}),
|
}),
|
||||||
kind: BinOpKind::Equal,
|
kind: BinOpKind::Equal,
|
||||||
},
|
},
|
||||||
span: 4..15,
|
span: 4..15,
|
||||||
},
|
},
|
||||||
body: Block {
|
body: vec![Spanned {
|
||||||
block: vec![Stmt {
|
item: Stmt::Print(Spanned {
|
||||||
kind: StmtKind::Print(Expr {
|
item: Expr::Literal(Value::Str("Buy Able products!".to_owned())),
|
||||||
kind: ExprKind::Literal(Value::Str("Buy Able products!".to_owned())),
|
span: 19..39,
|
||||||
span: 19..39,
|
}),
|
||||||
}),
|
span: 19..46,
|
||||||
span: 19..46,
|
}],
|
||||||
}],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
span: 0..48,
|
span: 0..48,
|
||||||
}];
|
}];
|
||||||
|
@ -666,20 +681,20 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tdark() {
|
fn tdark() {
|
||||||
let code = "T-Dark { var lang = /*lang*/ + lang; }";
|
let code = "T-Dark { var lang = /*lang*/ + lang; }";
|
||||||
let expected = &[Stmt {
|
let expected = &[Spanned {
|
||||||
kind: StmtKind::Var {
|
item: Stmt::Var {
|
||||||
ident: Ident {
|
ident: Spanned {
|
||||||
ident: "script".to_owned(),
|
item: "script".to_owned(),
|
||||||
span: 13..17,
|
span: 13..17,
|
||||||
},
|
},
|
||||||
init: Some(Expr {
|
init: Some(Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Str("script".to_owned())),
|
item: Expr::Literal(Value::Str("script".to_owned())),
|
||||||
span: 20..26,
|
span: 20..26,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Variable("script".to_owned()),
|
item: Expr::Variable("script".to_owned()),
|
||||||
span: 29..33,
|
span: 29..33,
|
||||||
}),
|
}),
|
||||||
kind: BinOpKind::Add,
|
kind: BinOpKind::Add,
|
||||||
|
@ -697,33 +712,33 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn cart_construction() {
|
fn cart_construction() {
|
||||||
let code = "[/*able*/ <= 1, /*script*/ <= 3 - 1] print;";
|
let code = "[/*able*/ <= 1, /*script*/ <= 3 - 1] print;";
|
||||||
let expected = &[Stmt {
|
let expected = &[Spanned {
|
||||||
kind: StmtKind::Print(Expr {
|
item: Stmt::Print(Spanned {
|
||||||
kind: ExprKind::Cart(vec![
|
item: Expr::Cart(vec![
|
||||||
(
|
(
|
||||||
Expr {
|
Spanned {
|
||||||
kind: ExprKind::Literal(Value::Str("able".to_owned())),
|
item: Expr::Literal(Value::Str("able".to_owned())),
|
||||||
span: 1..7,
|
span: 1..7,
|
||||||
},
|
},
|
||||||
Expr {
|
Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(1)),
|
item: Expr::Literal(Value::Int(1)),
|
||||||
span: 11..12,
|
span: 11..12,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Expr {
|
Spanned {
|
||||||
kind: ExprKind::Literal(Value::Str("script".to_owned())),
|
item: Expr::Literal(Value::Str("script".to_owned())),
|
||||||
span: 14..22,
|
span: 14..22,
|
||||||
},
|
},
|
||||||
Expr {
|
Spanned {
|
||||||
kind: ExprKind::BinOp {
|
item: Expr::BinOp {
|
||||||
kind: BinOpKind::Subtract,
|
kind: BinOpKind::Subtract,
|
||||||
lhs: Box::new(Expr {
|
lhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(3)),
|
item: Expr::Literal(Value::Int(3)),
|
||||||
span: 26..27,
|
span: 26..27,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expr {
|
rhs: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Int(1)),
|
item: Expr::Literal(Value::Int(1)),
|
||||||
span: 30..31,
|
span: 30..31,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -743,24 +758,24 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn cart_index() {
|
fn cart_index() {
|
||||||
let code = "[/*able*/ <= /*ablecorp*/][/*ablecorp*/] print;";
|
let code = "[/*able*/ <= /*ablecorp*/][/*ablecorp*/] print;";
|
||||||
let expected = &[Stmt {
|
let expected = &[Spanned {
|
||||||
kind: StmtKind::Print(Expr {
|
item: Stmt::Print(Spanned {
|
||||||
kind: ExprKind::Index {
|
item: Expr::Index {
|
||||||
expr: Box::new(Expr {
|
expr: Box::new(Spanned {
|
||||||
kind: ExprKind::Cart(vec![(
|
item: Expr::Cart(vec![(
|
||||||
Expr {
|
Spanned {
|
||||||
kind: ExprKind::Literal(Value::Str("able".to_owned())),
|
item: Expr::Literal(Value::Str("able".to_owned())),
|
||||||
span: 1..7,
|
span: 1..7,
|
||||||
},
|
},
|
||||||
Expr {
|
Spanned {
|
||||||
kind: ExprKind::Literal(Value::Str("ablecorp".to_owned())),
|
item: Expr::Literal(Value::Str("ablecorp".to_owned())),
|
||||||
span: 11..21,
|
span: 11..21,
|
||||||
},
|
},
|
||||||
)]),
|
)]),
|
||||||
span: 0..22,
|
span: 0..22,
|
||||||
}),
|
}),
|
||||||
index: Box::new(Expr {
|
index: Box::new(Spanned {
|
||||||
kind: ExprKind::Literal(Value::Str("ablecorp".to_owned())),
|
item: Expr::Literal(Value::Str("ablecorp".to_owned())),
|
||||||
span: 23..33,
|
span: 23..33,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,7 +12,7 @@ use std::{
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::{brian::INSTRUCTION_MAPPINGS, consts, ast::{Spanned, StmtKind}};
|
use crate::{ast::Block, brian::INSTRUCTION_MAPPINGS, consts};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||||
pub enum Abool {
|
pub enum Abool {
|
||||||
|
@ -58,7 +58,7 @@ pub enum Functio {
|
||||||
},
|
},
|
||||||
Able {
|
Able {
|
||||||
params: Vec<String>,
|
params: Vec<String>,
|
||||||
body: Vec<Spanned<StmtKind>>,
|
body: Block,
|
||||||
},
|
},
|
||||||
Builtin(BuiltinFunctio),
|
Builtin(BuiltinFunctio),
|
||||||
Chain {
|
Chain {
|
||||||
|
|
Loading…
Reference in a new issue