ast: implement literal and binary expressions
This commit is contained in:
parent
a0e09b9613
commit
4e7cfca1f3
4 changed files with 97 additions and 0 deletions
89
src/ast/expr.rs
Normal file
89
src/ast/expr.rs
Normal 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.
|
|
@ -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>
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue