Merge branch 'refactoring/ast-spans'

This commit is contained in:
Erin 2022-04-02 01:37:33 +02:00 committed by ondra05
commit 3b829d7e55
4 changed files with 297 additions and 318 deletions

View file

@ -8,68 +8,80 @@
//! just plain subroutines and they do not return any value, //! just plain subroutines and they do not return any value,
//! so their calls are statements. //! so their calls are statements.
use std::hash::Hash; use std::{fmt::Debug, hash::Hash};
use crate::variables::Value; use crate::variables::Value;
type Span = std::ops::Range<usize>; type Span = std::ops::Range<usize>;
#[derive(Debug, Clone)] #[derive(Clone)]
pub struct Ident { pub struct Spanned<T> {
pub ident: String, pub item: T,
pub span: Span, pub span: Span,
} }
impl Ident { impl<T> Spanned<T> {
pub fn new(ident: String, span: Span) -> Self { pub fn new(item: T, span: Span) -> Self {
Self { ident, span } Self { item, span }
} }
} }
impl PartialEq for Ident { impl<T: Debug> Debug for Spanned<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
write!(f, "{:#?}", self.item)
} else {
write!(f, "{:?}", self.item)
}?;
write!(f, " @ {:?}", self.span)
}
}
impl<T: PartialEq> PartialEq for Spanned<T> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.ident == other.ident self.item == other.item
} }
} }
impl Hash for Ident { impl<T: Hash> Hash for Spanned<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ident.hash(state) self.item.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<Expr> }, Index { indices: Vec<Spanned<Expr>> },
} }
pub struct InvalidAssignable; pub struct InvalidAssignable;
impl Assignable { impl Assignable {
pub fn from_expr(expr: Expr) -> Result<Assignable, InvalidAssignable> { pub fn from_expr(expr: Spanned<Expr>) -> Result<Assignable, InvalidAssignable> {
match expr.kind { 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: Expr, index: Expr) -> 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.kind { 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;
} }
@ -79,41 +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<Stmt>,
}
/// A syntactic unit expressing an effect. /// A syntactic unit expressing an effect.
#[derive(Debug, Clone)]
pub struct Stmt {
pub kind: StmtKind,
pub span: Span,
}
impl PartialEq for Stmt {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind
}
}
impl Hash for Stmt {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.kind.hash(state)
}
}
#[derive(Debug, PartialEq, Clone, Hash)] #[derive(Debug, PartialEq, Clone, Hash)]
pub enum StmtKind { pub enum Stmt {
// Control flow // Control flow
If { If {
cond: Expr, cond: Spanned<Expr>,
body: Block, body: Block,
}, },
Loop { Loop {
@ -123,85 +114,55 @@ pub enum StmtKind {
HopBack, HopBack,
Var { Var {
ident: Ident, ident: Spanned<String>,
init: Option<Expr>, init: Option<Spanned<Expr>>,
}, },
Assign { Assign {
assignable: Assignable, assignable: Assignable,
value: Expr, 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<Expr>, tape_len: Option<Spanned<Expr>>,
code: Vec<u8>, code: Vec<u8>,
}, },
Call { Call {
expr: Expr, expr: Spanned<Expr>,
args: Vec<Expr>, args: Vec<Spanned<Expr>>,
}, },
Print(Expr), Print(Spanned<Expr>),
Read(Assignable), Read(Assignable),
Melo(Ident), Melo(Spanned<String>),
Rlyeh, Rlyeh,
Rickroll, Rickroll,
} }
impl Stmt {
pub fn new(kind: StmtKind, span: Span) -> Self {
Self { kind, span }
}
}
/// 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, Clone)]
pub struct Expr {
pub kind: ExprKind,
pub span: Span,
}
impl PartialEq for Expr {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind
}
}
impl Hash for Expr {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.kind.hash(state)
}
}
#[derive(Debug, PartialEq, Clone, Hash)] #[derive(Debug, PartialEq, Clone, Hash)]
pub enum ExprKind { pub enum Expr {
BinOp { BinOp {
lhs: Box<Expr>, lhs: Box<Spanned<Expr>>,
rhs: Box<Expr>, rhs: Box<Spanned<Expr>>,
kind: BinOpKind, kind: BinOpKind,
}, },
Not(Box<Expr>), Not(Box<Spanned<Expr>>),
Literal(Value), Literal(Value),
Cart(Vec<(Expr, Expr)>), Cart(Vec<(Spanned<Expr>, Spanned<Expr>)>),
Index { Index {
expr: Box<Expr>, expr: Box<Spanned<Expr>>,
index: Box<Expr>, index: Box<Spanned<Expr>>,
}, },
Len(Box<Expr>), Len(Box<Spanned<Expr>>),
Variable(String), Variable(String),
} }
impl Expr {
pub fn new(kind: ExprKind, span: Span) -> Self {
Self { kind, span }
}
}
#[derive(Debug, PartialEq, Clone, Hash)] #[derive(Debug, PartialEq, Clone, Hash)]
pub enum BinOpKind { pub enum BinOpKind {
Add, Add,

View file

@ -19,7 +19,7 @@ use std::{
use rand::random; use rand::random;
use crate::{ use crate::{
ast::{Assignable, AssignableKind, Expr, ExprKind, Ident, Stmt, 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: &[Stmt]) -> 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 {
@ -126,7 +126,11 @@ impl ExecEnv {
/// ///
/// `interpret`-internal code should typically prefer this /// `interpret`-internal code should typically prefer this
/// function over `eval_stmts`. /// function over `eval_stmts`.
fn eval_stmts_hs(&mut self, stmts: &[Stmt], stackframe: bool) -> Result<HaltStatus, Error> { fn eval_stmts_hs(
&mut self,
stmts: &[Spanned<Stmt>],
stackframe: bool,
) -> Result<HaltStatus, Error> {
let init_depth = self.stack.len(); let init_depth = self.stack.len();
if stackframe { if stackframe {
@ -151,11 +155,11 @@ 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: &Expr) -> 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.kind { Ok(match &expr.item {
BinOp { lhs, rhs, kind } => { BinOp { lhs, rhs, kind } => {
let lhs = self.eval_expr(lhs)?; let lhs = self.eval_expr(lhs)?;
let rhs = self.eval_expr(rhs)?; let rhs = self.eval_expr(rhs)?;
@ -172,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)| {
@ -196,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: &Stmt) -> Result<HaltStatus, Error> { fn eval_stmt(&mut self, stmt: &Spanned<Stmt>) -> Result<HaltStatus, Error> {
match &stmt.kind { 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
@ -248,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;
@ -353,17 +354,19 @@ impl ExecEnv {
/// Call a function with the given arguments (i.e., actual /// Call a function with the given arguments (i.e., actual
/// parameters). If the function invocation fails for some reason, /// parameters). If the function invocation fails for some reason,
/// report the error at `span`. /// report the error at `span`.
fn fn_call(&mut self, func: Functio, args: &[Expr], span: &Range<usize>) -> Result<(), Error> { fn fn_call(
&mut self,
func: Functio,
args: &[Spanned<Expr>],
span: &Range<usize>,
) -> Result<(), Error> {
// Arguments that are ExprKind::Variable are pass by // Arguments that are ExprKind::Variable are pass by
// reference; all other expressions are pass by value. // reference; all other expressions are pass by value.
let args = args let args = args
.iter() .iter()
.map(|arg| { .map(|arg| {
if let ExprKind::Variable(name) = &arg.kind { 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)
} }
@ -513,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)));
} }
@ -526,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(),
}), }),
} }
@ -547,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(),
}), }),
} }
@ -575,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())
} }
@ -597,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::*;
@ -606,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,
@ -633,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,
@ -658,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,
@ -678,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,
@ -719,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(),
@ -730,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(),
@ -756,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(),

View file

@ -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<Stmt>, 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,33 +64,39 @@ 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<Stmt, 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 {
Token::If => Ok(Stmt::new(self.if_flow()?, start..self.lexer.span().end)), Token::If => Ok(Spanned::new(self.if_flow()?, start..self.lexer.span().end)),
Token::Functio => Ok(Stmt::new( Token::Functio => Ok(Spanned::new(
self.functio_flow()?, self.functio_flow()?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Bff => Ok(Stmt::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(Stmt::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(Stmt::new(self.melo_flow()?, start..self.lexer.span().end)), Token::Melo => Ok(Spanned::new(
Token::Loop => Ok(Stmt::new(self.loop_flow()?, start..self.lexer.span().end)), self.melo_flow()?,
Token::Break => Ok(Stmt::new(
self.semicolon_terminated(StmtKind::Break)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::HopBack => Ok(Stmt::new( Token::Loop => Ok(Spanned::new(
self.semicolon_terminated(StmtKind::HopBack)?, self.loop_flow()?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Rlyeh => Ok(Stmt::new( Token::Break => Ok(Spanned::new(
self.semicolon_terminated(StmtKind::Rlyeh)?, self.semicolon_terminated(Stmt::Break)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Rickroll => Ok(Stmt::new( Token::HopBack => Ok(Spanned::new(
self.semicolon_terminated(StmtKind::Rickroll)?, self.semicolon_terminated(Stmt::HopBack)?,
start..self.lexer.span().end,
)),
Token::Rlyeh => Ok(Spanned::new(
self.semicolon_terminated(Stmt::Rlyeh)?,
start..self.lexer.span().end,
)),
Token::Rickroll => Ok(Spanned::new(
self.semicolon_terminated(Stmt::Rickroll)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
@ -99,7 +105,7 @@ impl<'source> Parser<'source> {
| Token::Integer(_) | Token::Integer(_)
| Token::Not | Token::Not
| Token::LeftBracket | Token::LeftBracket
| Token::LeftParen => Ok(Stmt::new( | Token::LeftParen => Ok(Spanned::new(
self.value_flow(token)?, self.value_flow(token)?,
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<Expr>) -> Result<Expr, 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,
@ -155,20 +165,20 @@ impl<'source> Parser<'source> {
match token { match token {
// Values // Values
Token::Identifier(i) => Ok(Expr::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
}), }),
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Integer(i) => Ok(Expr::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(Expr::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
@ -177,11 +187,14 @@ impl<'source> Parser<'source> {
)), )),
Token::LeftBracket => match buf.take() { Token::LeftBracket => match buf.take() {
Some(buf) => Ok(Expr::new( Some(buf) => Ok(Spanned::new(
self.index_flow(buf)?, self.index_flow(buf)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
None => Ok(Expr::new(self.cart_flow()?, start..self.lexer.span().end)), None => Ok(Spanned::new(
self.cart_flow()?,
start..self.lexer.span().end,
)),
}, },
// Operations // Operations
@ -192,7 +205,7 @@ impl<'source> Parser<'source> {
| Token::EqualEqual | Token::EqualEqual
| Token::NotEqual | Token::NotEqual
| Token::LessThan | Token::LessThan
| Token::GreaterThan => Ok(Expr::new( | Token::GreaterThan => Ok(Spanned::new(
self.binop_flow( self.binop_flow(
BinOpKind::from_token(token).map_err(|e| Error::new(e, self.lexer.span()))?, BinOpKind::from_token(token).map_err(|e| Error::new(e, self.lexer.span()))?,
buf, buf,
@ -200,10 +213,10 @@ impl<'source> Parser<'source> {
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Not => Ok(Expr::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: Expr) -> 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<Expr>) -> 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<Expr, 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: Expr) -> 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,
}), }),
}, },

View file

@ -12,7 +12,7 @@ use std::{
use rand::Rng; use rand::Rng;
use crate::{ast::Stmt, brian::INSTRUCTION_MAPPINGS, consts}; 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<Stmt>, body: Block,
}, },
Builtin(BuiltinFunctio), Builtin(BuiltinFunctio),
Chain { Chain {