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
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>,
|
|
},
|
|
Target {
|
|
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::Target { 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::Target { name, content } => "target",
|
|
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",
|
|
}
|
|
)
|
|
}
|
|
}
|