ast: implement literal and binary expressions

This commit is contained in:
anna 2021-04-19 20:33:55 +02:00
parent a0e09b9613
commit 4e7cfca1f3
Signed by: fef
GPG key ID: EC22E476DC2D3D84
4 changed files with 97 additions and 0 deletions

89
src/ast/expr.rs Normal file
View file

@ -0,0 +1,89 @@
// See the end of this file for copyright and license terms.
use super::val;
use super::val::{Val, TypeError};
/// An `Expr` is any construct that can be resolved to a [`Val`](super::val::Val).
/// It is always pure, meaning there is no internal state and it will always evaluate to
/// the same result no matter how often it is called.
pub trait Expr {
fn clone(&self) -> Box<dyn Expr>;
fn eval(&self) -> Result<Box<dyn Val>, TypeError>;
}
pub struct LiteralExpr {
val: Box<dyn Val>,
}
impl Expr for LiteralExpr {
fn clone(&self) -> Box<dyn Expr> {
Box::new(LiteralExpr {
val: self.val.clone(),
})
}
fn eval(&self) -> Result<Box<dyn Val>, TypeError> {
Ok(self.val.clone())
}
}
#[derive(Copy, Clone)]
pub enum BinOp {
Plus,
Minus,
}
impl BinOp {
pub fn exec(&self, left: &dyn Expr, right: &dyn Expr) -> Result<Box<dyn Val>, TypeError> {
// TODO: implement string concatenation and decide whether implicit
// typecasts are a good idea (spoiler: they're not)
// TODO: it might actually be smarter to implement unary/binary
// operators in the Val trait rather than here, idk
let left_val = *left.eval()?.int()?;
let right_val = *right.eval()?.int()?;
Ok(val::int(match self {
BinOp::Plus => left_val + right_val,
BinOp::Minus => left_val - right_val,
}))
}
}
pub struct BinExpr {
left: Box<dyn Expr>,
op: BinOp,
right: Box<dyn Expr>,
}
impl BinExpr {
pub fn new(left: Box<dyn Expr>, op: BinOp, right: Box<dyn Expr>) -> BinExpr {
BinExpr {
left,
op,
right,
}
}
}
impl Expr for BinExpr {
fn clone(&self) -> Box<dyn Expr> {
Box::new(BinExpr::new(self.left.clone(), self.op, self.right.clone()))
}
fn eval(&self) -> Result<Box<dyn Val>, TypeError> {
self.op.exec(self.left.as_ref(), self.right.as_ref())
}
}
// Copyright (C) 2021 Fefie <owo@fef.moe>
// This file is part of gayconf.
//
// gayconf is non-violent software: you can use, redistribute,
// and/or modify it under the terms of the CNPLv6+ as found
// in the LICENSE file in the source code root directory or
// at <https://git.pixie.town/thufie/CNPL>.
//
// gayconf comes with ABSOLUTELY NO WARRANTY, to the extent
// permitted by applicable law. See the CNPL for details.

View file

@ -1,5 +1,6 @@
// See the end of this file for copyright and license terms.
pub mod expr;
pub mod val;
// Copyright (C) 2021 Fefie <owo@fef.moe>

View file

@ -9,6 +9,7 @@ pub enum Type {
String,
}
/// The (immutable) result of evaluating an [`Expr`](super::expr::Expr).
pub trait Val {
fn clone(&self) -> Box<dyn Val>;

View file

@ -121,6 +121,12 @@ impl GetNodeVal<String> for Config {
}
}
pub trait ConfigError {
fn msg(&self) -> &str;
fn line(&self) -> usize;
fn col(&self) -> usize;
}
// Copyright (C) 2021 Fefie <owo@fef.moe>
// This file is part of gayconf.
//