Generalised Spanned items

This commit is contained in:
Erin 2022-04-02 01:22:46 +02:00 committed by ondra05
parent a6ecf782db
commit ce2de21d9b
4 changed files with 102 additions and 105 deletions

View file

@ -8,12 +8,48 @@
//! 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(Clone)]
pub struct Spanned<T> {
pub item: T,
pub span: Span,
}
impl<T> Spanned<T> {
pub fn new(item: T, span: Span) -> Self {
Self { item, span }
}
}
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 {
self.item == other.item
}
}
impl<T: Hash> Hash for Spanned<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.item.hash(state);
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Ident { pub struct Ident {
pub ident: String, pub ident: String,
@ -47,14 +83,14 @@ pub struct Assignable {
#[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<ExprKind>> },
} }
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<ExprKind>) -> Result<Assignable, InvalidAssignable> {
match expr.kind { match expr.item {
ExprKind::Variable(ident) => Ok(Assignable { ExprKind::Variable(ident) => Ok(Assignable {
ident: Ident::new(ident, expr.span), ident: Ident::new(ident, expr.span),
kind: AssignableKind::Variable, kind: AssignableKind::Variable,
@ -64,10 +100,10 @@ impl Assignable {
} }
} }
fn from_index(mut buf: Expr, index: Expr) -> Result<Assignable, InvalidAssignable> { fn from_index(mut buf: Spanned<ExprKind>, index: Spanned<ExprKind>) -> 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, ExprKind::Variable(ident) => break ident,
ExprKind::Index { expr, index } => { ExprKind::Index { expr, index } => {
indices.push(*index); indices.push(*index);
@ -87,33 +123,15 @@ impl Assignable {
#[derive(Debug, PartialEq, Clone, Hash)] #[derive(Debug, PartialEq, Clone, Hash)]
pub struct Block { pub struct Block {
pub block: Vec<Stmt>, pub block: Vec<Spanned<StmtKind>>,
} }
/// 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 StmtKind {
// Control flow // Control flow
If { If {
cond: Expr, cond: Spanned<ExprKind>,
body: Block, body: Block,
}, },
Loop { Loop {
@ -124,11 +142,11 @@ pub enum StmtKind {
Var { Var {
ident: Ident, ident: Ident,
init: Option<Expr>, init: Option<Spanned<ExprKind>>,
}, },
Assign { Assign {
assignable: Assignable, assignable: Assignable,
value: Expr, value: Spanned<ExprKind>,
}, },
Functio { Functio {
@ -138,70 +156,40 @@ pub enum StmtKind {
}, },
BfFunctio { BfFunctio {
ident: Ident, ident: Ident,
tape_len: Option<Expr>, tape_len: Option<Spanned<ExprKind>>,
code: Vec<u8>, code: Vec<u8>,
}, },
Call { Call {
expr: Expr, expr: Spanned<ExprKind>,
args: Vec<Expr>, args: Vec<Spanned<ExprKind>>,
}, },
Print(Expr), Print(Spanned<ExprKind>),
Read(Assignable), Read(Assignable),
Melo(Ident), Melo(Ident),
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 ExprKind {
BinOp { BinOp {
lhs: Box<Expr>, lhs: Box<Spanned<ExprKind>>,
rhs: Box<Expr>, rhs: Box<Spanned<ExprKind>>,
kind: BinOpKind, kind: BinOpKind,
}, },
Not(Box<Expr>), Not(Box<Spanned<ExprKind>>),
Literal(Value), Literal(Value),
Cart(Vec<(Expr, Expr)>), Cart(Vec<(Spanned<ExprKind>, Spanned<ExprKind>)>),
Index { Index {
expr: Box<Expr>, expr: Box<Spanned<ExprKind>>,
index: Box<Expr>, index: Box<Spanned<ExprKind>>,
}, },
Len(Box<Expr>), Len(Box<Spanned<ExprKind>>),
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, ExprKind, Ident, Spanned, StmtKind},
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<StmtKind>]) -> 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<StmtKind>],
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<ExprKind>) -> Result<Value, Error> {
use crate::ast::BinOpKind::*; use crate::ast::BinOpKind::*;
use crate::ast::ExprKind::*; use crate::ast::ExprKind::*;
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)?;
@ -204,8 +208,8 @@ impl ExecEnv {
} }
/// 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<StmtKind>) -> Result<HaltStatus, Error> {
match &stmt.kind { match &stmt.item {
StmtKind::Print(expr) => { StmtKind::Print(expr) => {
println!("{}", self.eval_expr(expr)?); println!("{}", self.eval_expr(expr)?);
} }
@ -353,13 +357,18 @@ 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<ExprKind>],
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 ExprKind::Variable(name) = &arg.item {
self.get_var_rc(&Ident { self.get_var_rc(&Ident {
ident: name.to_owned(), ident: name.to_owned(),
span: arg.span.clone(), span: arg.span.clone(),

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<Vec<Spanned<StmtKind>>, 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 {
@ -64,32 +64,32 @@ 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<StmtKind>, 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(self.melo_flow()?, start..self.lexer.span().end)),
Token::Loop => Ok(Stmt::new(self.loop_flow()?, start..self.lexer.span().end)), Token::Loop => Ok(Spanned::new(self.loop_flow()?, start..self.lexer.span().end)),
Token::Break => Ok(Stmt::new( Token::Break => Ok(Spanned::new(
self.semicolon_terminated(StmtKind::Break)?, self.semicolon_terminated(StmtKind::Break)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::HopBack => Ok(Stmt::new( Token::HopBack => Ok(Spanned::new(
self.semicolon_terminated(StmtKind::HopBack)?, self.semicolon_terminated(StmtKind::HopBack)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Rlyeh => Ok(Stmt::new( Token::Rlyeh => Ok(Spanned::new(
self.semicolon_terminated(StmtKind::Rlyeh)?, self.semicolon_terminated(StmtKind::Rlyeh)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Rickroll => Ok(Stmt::new( Token::Rickroll => Ok(Spanned::new(
self.semicolon_terminated(StmtKind::Rickroll)?, self.semicolon_terminated(StmtKind::Rickroll)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
@ -99,7 +99,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,
)), )),
@ -147,7 +147,7 @@ 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<ExprKind>>) -> Result<Spanned<ExprKind>, 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,7 +155,7 @@ 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 { ExprKind::Variable(if self.tdark {
i.replace("lang", "script") i.replace("lang", "script")
} else { } else {
@ -163,11 +163,11 @@ impl<'source> Parser<'source> {
}), }),
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)), ExprKind::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 { ExprKind::Literal(Value::Str(if self.tdark {
s.replace("lang", "script") s.replace("lang", "script")
} else { } else {
@ -177,11 +177,11 @@ 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 +192,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,7 +200,7 @@ 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)?)) ExprKind::Not(Box::new(self.parse_expr(next, buf)?))
@ -262,7 +262,7 @@ impl<'source> Parser<'source> {
/// 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<ExprKind>) -> Result<ExprKind, Error> {
let mut buf = None; let mut buf = None;
Ok(loop { Ok(loop {
match self.checked_next()? { match self.checked_next()? {
@ -285,7 +285,7 @@ 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(&mut self, kind: BinOpKind, lhs: &mut Option<Spanned<ExprKind>>) -> Result<ExprKind, Error> {
Ok(ExprKind::BinOp { Ok(ExprKind::BinOp {
lhs: Box::new( lhs: Box::new(
lhs.take() lhs.take()
@ -303,7 +303,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<ExprKind>, Error> {
let mut buf = None; let mut buf = None;
Ok(loop { Ok(loop {
match self.checked_next()? { match self.checked_next()? {
@ -497,7 +497,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<ExprKind>) -> Result<StmtKind, Error> {
let mut args = vec![]; let mut args = vec![];
let mut buf = None; let mut buf = None;
loop { loop {

View file

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