You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
4.8 KiB
Rust

use std::fmt;
use std::fmt::Formatter;
use crate::error::Error;
use crate::lex::token;
use crate::lex::token::Token;
#[derive(Debug)]
pub enum Node {
Ident(String),
DepList(Box<Node>),
SourceList(Box<Node>),
Int(i128),
String(String),
Array(Vec<Node>),
UnaryExpr {
op: Operator,
node: Box<Node>,
},
BinaryExpr {
op: Operator,
lhs: Box<Node>,
rhs: Box<Node>,
},
TypeExpr(Box<Node>),
SetExpr {
name: Box<Node>,
val: Box<Node>,
},
Module {
name: Box<Node>,
content: Vec<Node>,
},
File {
name: String,
content: Vec<Node>,
},
}
#[derive(Debug)]
pub enum Operator {
Eq,
Plus,
Minus,
Asterisk,
Slash,
Percent,
}
impl Node {
pub fn walk(&self, cb: fn(node: &Node, depth: u32)) {
self.visit(cb, 0);
}
fn visit(&self, cb: fn(node: &Node, depth: u32), current_depth: u32) {
cb(self, current_depth);
let depth = current_depth + 1;
match self {
Node::DepList(list) => list.visit(cb, depth),
Node::SourceList(list) => list.visit(cb, depth),
Node::Array(elements) => {
for node in elements {
node.visit(cb, depth);
}
}
Node::UnaryExpr { op, node } => node.visit(cb, depth),
Node::BinaryExpr { op, lhs, rhs } => {
lhs.visit(cb, depth);
rhs.visit(cb, depth);
}
Node::TypeExpr(node) => node.visit(cb, depth),
Node::SetExpr { name, val } => {
name.visit(cb, depth);
val.visit(cb, depth);
}
Node::Module { name, content } => {
name.visit(cb, depth);
for n in content {
n.visit(cb, depth);
}
}
Node::File { name, content } => {
for n in content {
n.visit(cb, depth);
}
}
_ => return,
}
}
}
impl fmt::Display for Node {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut tmp: String;
write!(
f,
"{}",
match self {
Node::Ident(name) => name.as_str(),
Node::Int(i) => {
tmp = format!("{}", i);
tmp.as_str()
}
Node::String(s) => s.as_str(),
Node::DepList(_) => "depend",
Node::SourceList(_) => "source",
Node::Array(_) => "<array>",
Node::UnaryExpr { op, node } => op.raw(),
Node::BinaryExpr { op, lhs, rhs } => op.raw(),
Node::TypeExpr(_) => "type",
Node::SetExpr { name, val } => "set",
Node::Module { name, content } => "module",
Node::File { name, content } => "file",
}
)
}
}
impl Operator {
pub fn from_token(token: &Token) -> Result<Operator, Error> {
match token.kind {
token::Kind::Eq => Ok(Operator::Eq),
token::Kind::Plus => Ok(Operator::Plus),
token::Kind::Minus => Ok(Operator::Minus),
token::Kind::Asterisk => Ok(Operator::Asterisk),
token::Kind::Slash => Ok(Operator::Slash),
token::Kind::Percent => Ok(Operator::Percent),
_ => Err(Error::syntax_error(
token.pos.clone(),
format!("\"{}\" is not an operator", token.raw),
)),
}
}
pub fn raw(&self) -> &'static str {
match self {
Operator::Eq => "=",
Operator::Plus => "+",
Operator::Minus => "-",
Operator::Asterisk => "*",
Operator::Slash => "/",
Operator::Percent => "%",
}
}
}
impl fmt::Display for Operator {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.raw())
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Type {
/// For identifier tokens (evaluates at runtime)
Unknown,
/// For expressions that don't emit a value
None,
Int,
String,
}
impl Type {
pub fn from_token(token: &Token) -> Option<Type> {
match token.kind {
token::Kind::IntLiteral => Some(Type::Int),
token::Kind::StringLiteral => Some(Type::String),
_ => None,
}
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Type::Unknown => "<unknown>",
Type::None => "()",
Type::Int => "int",
Type::String => "string",
}
)
}
}