|
|
|
@ -1,75 +1,93 @@
|
|
|
|
|
use std::fmt;
|
|
|
|
|
use std::fmt::Formatter;
|
|
|
|
|
|
|
|
|
|
use crate::error::Error;
|
|
|
|
|
|
|
|
|
|
use crate::lex::token;
|
|
|
|
|
use crate::lex::token::Token;
|
|
|
|
|
use crate::lex::token::{Position, Token};
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum Node {
|
|
|
|
|
Break,
|
|
|
|
|
Ident(String),
|
|
|
|
|
DepList(Box<Node>),
|
|
|
|
|
SourceList(Box<Node>),
|
|
|
|
|
Bool(bool),
|
|
|
|
|
Int(i128),
|
|
|
|
|
String(String),
|
|
|
|
|
Array(Vec<Node>),
|
|
|
|
|
Block(Vec<Node>),
|
|
|
|
|
Fn {
|
|
|
|
|
name: Option<Box<Node>>,
|
|
|
|
|
params: Vec<Node>,
|
|
|
|
|
body: Box<Node>,
|
|
|
|
|
},
|
|
|
|
|
ArrayExpr {
|
|
|
|
|
// array access
|
|
|
|
|
array: Box<Node>,
|
|
|
|
|
index: Box<Node>,
|
|
|
|
|
},
|
|
|
|
|
CallExpr {
|
|
|
|
|
// function call
|
|
|
|
|
func: Box<Node>,
|
|
|
|
|
params: Vec<Node>,
|
|
|
|
|
},
|
|
|
|
|
IfStmt {
|
|
|
|
|
condition: Box<Node>,
|
|
|
|
|
then_block: Box<Node>,
|
|
|
|
|
else_block: Option<Box<Node>>,
|
|
|
|
|
},
|
|
|
|
|
ReturnStmt(Box<Node>),
|
|
|
|
|
ForStmt {
|
|
|
|
|
setup: Option<Box<Node>>,
|
|
|
|
|
condition: Option<Box<Node>>,
|
|
|
|
|
exec: Option<Box<Node>>,
|
|
|
|
|
body: Box<Node>,
|
|
|
|
|
},
|
|
|
|
|
WhileStmt {
|
|
|
|
|
condition: Box<Node>,
|
|
|
|
|
block: Box<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: Box<Node>,
|
|
|
|
|
},
|
|
|
|
|
File {
|
|
|
|
|
name: String,
|
|
|
|
|
content: Vec<Node>,
|
|
|
|
|
},
|
|
|
|
|
Break(Position),
|
|
|
|
|
Ident(Position, String),
|
|
|
|
|
DepList(Position, Box<Node>),
|
|
|
|
|
SourceList(Position, Box<Node>),
|
|
|
|
|
Bool(Position, bool),
|
|
|
|
|
Int(Position, i128),
|
|
|
|
|
String(Position, String),
|
|
|
|
|
Array(Position, Vec<Node>),
|
|
|
|
|
Block(Position, Vec<Node>),
|
|
|
|
|
Fn(Position, FnStmt),
|
|
|
|
|
ArrayExpr(Position, ArrayExpr),
|
|
|
|
|
CallExpr(Position, CallExpr),
|
|
|
|
|
IfStmt(Position, IfStmt),
|
|
|
|
|
ReturnStmt(Position, Box<Node>),
|
|
|
|
|
ForStmt(Position, ForStmt),
|
|
|
|
|
WhileStmt(Position, WhileStmt),
|
|
|
|
|
UnaryExpr(Position, UnaryExpr),
|
|
|
|
|
BinaryExpr(Position, BinaryExpr),
|
|
|
|
|
TypeStmt(Position, Box<Node>),
|
|
|
|
|
SetStmt(Position, SetStmt),
|
|
|
|
|
TargetStmt(Position, TargetStmt),
|
|
|
|
|
File(Position, File),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct File {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub content: Vec<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct FnStmt {
|
|
|
|
|
pub name: Option<Box<Node>>,
|
|
|
|
|
pub params: Vec<Node>,
|
|
|
|
|
pub body: Box<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct IfStmt {
|
|
|
|
|
pub condition: Box<Node>,
|
|
|
|
|
pub then_body: Box<Node>,
|
|
|
|
|
pub else_body: Option<Box<Node>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct ForStmt {
|
|
|
|
|
pub setup: Option<Box<Node>>,
|
|
|
|
|
pub condition: Option<Box<Node>>,
|
|
|
|
|
pub exec: Option<Box<Node>>,
|
|
|
|
|
pub body: Box<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct WhileStmt {
|
|
|
|
|
pub condition: Box<Node>,
|
|
|
|
|
pub body: Box<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct SetStmt {
|
|
|
|
|
pub name: Box<Node>,
|
|
|
|
|
pub val: Box<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct TargetStmt {
|
|
|
|
|
pub name: Box<Node>,
|
|
|
|
|
pub val: Box<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct BinaryExpr {
|
|
|
|
|
pub lhs: Box<Node>,
|
|
|
|
|
pub op: Operator,
|
|
|
|
|
pub rhs: Box<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct UnaryExpr {
|
|
|
|
|
pub op: Operator,
|
|
|
|
|
pub rhs: Box<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct CallExpr {
|
|
|
|
|
pub func: Box<Node>,
|
|
|
|
|
pub params: Vec<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct ArrayExpr {
|
|
|
|
|
pub array: Box<Node>,
|
|
|
|
|
pub index: Box<Node>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
@ -108,136 +126,237 @@ pub enum Operator {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Node {
|
|
|
|
|
pub fn assert_ident(&self) -> Result<&String, Error> {
|
|
|
|
|
match self {
|
|
|
|
|
Node::Ident(_, name) => Ok(name),
|
|
|
|
|
_ => Err(Error::syntax_error(
|
|
|
|
|
self.pos().clone(),
|
|
|
|
|
format!("Expected an identifier, got {}", self),
|
|
|
|
|
)),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn walk(&self, cb: fn(node: &Node, depth: u32)) {
|
|
|
|
|
self.visit(cb, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn pos(&self) -> &Position {
|
|
|
|
|
match self {
|
|
|
|
|
Node::Break(pos) => pos,
|
|
|
|
|
Node::Ident(pos, _) => pos,
|
|
|
|
|
Node::Bool(pos, _) => pos,
|
|
|
|
|
Node::Int(pos, _) => pos,
|
|
|
|
|
Node::String(pos, _) => pos,
|
|
|
|
|
Node::Block(pos, _) => pos,
|
|
|
|
|
Node::Fn(pos, _) => pos,
|
|
|
|
|
Node::ReturnStmt(pos, _) => pos,
|
|
|
|
|
Node::DepList(pos, _) => pos,
|
|
|
|
|
Node::SourceList(pos, _) => pos,
|
|
|
|
|
Node::Array(pos, _) => pos,
|
|
|
|
|
Node::ArrayExpr(pos, _) => pos,
|
|
|
|
|
Node::CallExpr(pos, _) => pos,
|
|
|
|
|
Node::IfStmt(pos, _) => pos,
|
|
|
|
|
Node::ForStmt(pos, _) => pos,
|
|
|
|
|
Node::WhileStmt(pos, _) => pos,
|
|
|
|
|
Node::UnaryExpr(pos, _) => pos,
|
|
|
|
|
Node::BinaryExpr(pos, _) => pos,
|
|
|
|
|
Node::TypeStmt(pos, _) => pos,
|
|
|
|
|
Node::SetStmt(pos, _) => pos,
|
|
|
|
|
Node::TargetStmt(pos, _) => pos,
|
|
|
|
|
Node::File(pos, _) => pos,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) => {
|
|
|
|
|
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::Block(statements) => {
|
|
|
|
|
Node::Block(_, statements) => {
|
|
|
|
|
for node in statements {
|
|
|
|
|
node.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Node::Fn { name, params, body } => {
|
|
|
|
|
if let Some(n) = name {
|
|
|
|
|
Node::Fn(_, func) => {
|
|
|
|
|
if let Some(n) = &func.name {
|
|
|
|
|
n.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
for p in params {
|
|
|
|
|
for p in &func.params {
|
|
|
|
|
p.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
body.visit(cb, depth);
|
|
|
|
|
func.body.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
Node::ArrayExpr { array, index } => {
|
|
|
|
|
array.visit(cb, depth);
|
|
|
|
|
index.visit(cb, depth);
|
|
|
|
|
Node::ArrayExpr(_, expr) => {
|
|
|
|
|
expr.array.visit(cb, depth);
|
|
|
|
|
expr.index.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
Node::CallExpr { func, params } => {
|
|
|
|
|
func.visit(cb, depth);
|
|
|
|
|
for p in params {
|
|
|
|
|
Node::CallExpr(_, expr) => {
|
|
|
|
|
expr.func.visit(cb, depth);
|
|
|
|
|
for p in &expr.params {
|
|
|
|
|
p.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Node::IfStmt {
|
|
|
|
|
condition,
|
|
|
|
|
then_block,
|
|
|
|
|
else_block,
|
|
|
|
|
} => {
|
|
|
|
|
condition.visit(cb, depth);
|
|
|
|
|
then_block.visit(cb, depth);
|
|
|
|
|
if let Some(eb) = else_block {
|
|
|
|
|
Node::IfStmt(_, stmt) => {
|
|
|
|
|
stmt.condition.visit(cb, depth);
|
|
|
|
|
stmt.then_body.visit(cb, depth);
|
|
|
|
|
if let Some(eb) = &stmt.else_body {
|
|
|
|
|
eb.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Node::ForStmt { setup, condition, exec, body } => {
|
|
|
|
|
if let Some(s) = setup {
|
|
|
|
|
Node::ForStmt(_, stmt) => {
|
|
|
|
|
if let Some(s) = &stmt.setup {
|
|
|
|
|
s.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
if let Some(c) = condition {
|
|
|
|
|
if let Some(c) = &stmt.condition {
|
|
|
|
|
c.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
if let Some(e) = exec {
|
|
|
|
|
if let Some(e) = &stmt.exec {
|
|
|
|
|
e.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
body.visit(cb, depth);
|
|
|
|
|
stmt.body.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
Node::WhileStmt { condition, block } => {
|
|
|
|
|
condition.visit(cb, depth);
|
|
|
|
|
block.visit(cb, depth);
|
|
|
|
|
Node::WhileStmt(_, stmt) => {
|
|
|
|
|
stmt.condition.visit(cb, depth);
|
|
|
|
|
stmt.body.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
Node::ReturnStmt(node) => 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::ReturnStmt(_, node) => node.visit(cb, depth),
|
|
|
|
|
Node::UnaryExpr(_, expr) => expr.rhs.visit(cb, depth),
|
|
|
|
|
Node::BinaryExpr(_, expr) => {
|
|
|
|
|
expr.lhs.visit(cb, depth);
|
|
|
|
|
expr.rhs.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
Node::TypeExpr(node) => node.visit(cb, depth),
|
|
|
|
|
Node::SetExpr { name, val } => {
|
|
|
|
|
name.visit(cb, depth);
|
|
|
|
|
val.visit(cb, depth);
|
|
|
|
|
Node::TypeStmt(_, expr) => expr.visit(cb, depth),
|
|
|
|
|
Node::SetStmt(_, expr) => {
|
|
|
|
|
expr.name.visit(cb, depth);
|
|
|
|
|
expr.val.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
Node::Target { name, content } => {
|
|
|
|
|
name.visit(cb, depth);
|
|
|
|
|
content.visit(cb, depth);
|
|
|
|
|
Node::TargetStmt(_, stmt) => {
|
|
|
|
|
stmt.name.visit(cb, depth);
|
|
|
|
|
stmt.val.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
Node::File { name, content } => {
|
|
|
|
|
for n in content {
|
|
|
|
|
Node::File(_, file) => {
|
|
|
|
|
for n in &file.content {
|
|
|
|
|
n.visit(cb, depth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => return,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_fn(pos: Position, name: Option<Node>, params: Vec<Node>, body: Node) -> Node {
|
|
|
|
|
let name = if let Some(name) = name {
|
|
|
|
|
Some(Box::new(name))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
Node::Fn(pos, FnStmt { name, params, body: Box::new(body) })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_binary_expr(pos: Position, lhs: Node, op: Operator, rhs: Node) -> Node {
|
|
|
|
|
Node::BinaryExpr(pos, BinaryExpr { lhs: Box::new(lhs), op, rhs: Box::new(rhs) })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_unary_expr(pos: Position, op: Operator, rhs: Node) -> Node {
|
|
|
|
|
Node::UnaryExpr(pos, UnaryExpr { op, rhs: Box::new(rhs) })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_call_expr(pos: Position, func: Node, params: Vec<Node>) -> Node {
|
|
|
|
|
Node::CallExpr(pos, CallExpr { func: Box::new(func), params })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_array_expr(pos: Position, array: Node, index: Node) -> Node {
|
|
|
|
|
Node::ArrayExpr(pos, ArrayExpr { array: Box::new(array), index: Box::new(index) })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_set_stmt(pos: Position, name: Node, val: Node) -> Node {
|
|
|
|
|
Node::SetStmt(pos, SetStmt { name: Box::new(name), val: Box::new(val) })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_target_stmt(pos: Position, name: Node, val: Node) -> Node {
|
|
|
|
|
Node::TargetStmt(pos, TargetStmt { name: Box::new(name), val: Box::new(val) })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_if_stmt(pos: Position, condition: Node, then_body: Node, else_body: Option<Node>) -> Node {
|
|
|
|
|
let else_body = if let Some(else_body) = else_body {
|
|
|
|
|
Some(Box::new(else_body))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
Node::IfStmt(pos, IfStmt {
|
|
|
|
|
condition: Box::new(condition),
|
|
|
|
|
then_body: Box::new(then_body),
|
|
|
|
|
else_body,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_while_stmt(pos: Position, condition: Node, body: Node) -> Node {
|
|
|
|
|
Node::WhileStmt(pos, WhileStmt {
|
|
|
|
|
condition: Box::new(condition),
|
|
|
|
|
body: Box::new(body)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn make_for_stmt(pos: Position, setup: Option<Node>, condition: Option<Node>, exec: Option<Node>, body: Node) -> Node {
|
|
|
|
|
let setup = if let Some(setup) = setup {
|
|
|
|
|
Some(Box::new(setup))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
let condition = if let Some(condition) = condition {
|
|
|
|
|
Some(Box::new(condition))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
let exec = if let Some(exec) = exec {
|
|
|
|
|
Some(Box::new(exec))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
Node::ForStmt(pos, ForStmt { setup, condition, exec, body: Box::new(body) })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for Node {
|
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
let tmp: String;
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"{}",
|
|
|
|
|
match self {
|
|
|
|
|
Node::Break => "<break>",
|
|
|
|
|
Node::Ident(name) => name.as_str(),
|
|
|
|
|
Node::Bool(b) => {
|
|
|
|
|
Node::Break(_) => "<break>",
|
|
|
|
|
Node::Ident(_, name) => name.as_str(),
|
|
|
|
|
Node::Bool(_, b) => {
|
|
|
|
|
tmp = format!("{}", b);
|
|
|
|
|
tmp.as_str()
|
|
|
|
|
}
|
|
|
|
|
Node::Int(i) => {
|
|
|
|
|
Node::Int(_, i) => {
|
|
|
|
|
tmp = format!("{}", i);
|
|
|
|
|
tmp.as_str()
|
|
|
|
|
}
|
|
|
|
|
Node::String(s) => s.as_str(),
|
|
|
|
|
Node::Block(_) => "<block>",
|
|
|
|
|
Node::Fn { name, params, body } => "fn",
|
|
|
|
|
Node::ReturnStmt(_) => "return",
|
|
|
|
|
Node::DepList(_) => "depend",
|
|
|
|
|
Node::SourceList(_) => "source",
|
|
|
|
|
Node::Array(_) => "<array>",
|
|
|
|
|
Node::ArrayExpr { array, index } => "<array-access>",
|
|
|
|
|
Node::CallExpr { func, params } => "<call>",
|
|
|
|
|
Node::IfStmt {
|
|
|
|
|
condition,
|
|
|
|
|
then_block,
|
|
|
|
|
else_block,
|
|
|
|
|
} => "<if>",
|
|
|
|
|
Node::ForStmt { setup, condition, exec, body } => "<for>",
|
|
|
|
|
Node::WhileStmt { condition, block } => "<while>",
|
|
|
|
|
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",
|
|
|
|
|
Node::String(_, s) => s.as_str(),
|
|
|
|
|
Node::Block(_, _) => "<block>",
|
|
|
|
|
Node::Fn(_, _) => "fn",
|
|
|
|
|
Node::ReturnStmt(_, _) => "return",
|
|
|
|
|
Node::DepList(_, _) => "depend",
|
|
|
|
|
Node::SourceList(_, _) => "source",
|
|
|
|
|
Node::Array(_, _) => "<array>",
|
|
|
|
|
Node::ArrayExpr(_, _) => "<array-access>",
|
|
|
|
|
Node::CallExpr(_, _) => "<call>",
|
|
|
|
|
Node::IfStmt(_, _) => "<if>",
|
|
|
|
|
Node::ForStmt(_, _) => "<for>",
|
|
|
|
|
Node::WhileStmt(_, _) => "<while>",
|
|
|
|
|
Node::UnaryExpr(_, expr) => expr.op.raw(),
|
|
|
|
|
Node::BinaryExpr(_, expr) => expr.op.raw(),
|
|
|
|
|
Node::TypeStmt(_, _) => "type",
|
|
|
|
|
Node::SetStmt(_, _) => "set",
|
|
|
|
|
Node::TargetStmt(_, _) => "target",
|
|
|
|
|
Node::File(pos, _) => pos.file.as_str(),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
@ -321,7 +440,7 @@ impl Operator {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for Operator {
|
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
write!(f, "{}", self.raw())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -331,9 +450,12 @@ pub enum Type {
|
|
|
|
|
/// For identifier tokens (evaluates at runtime)
|
|
|
|
|
Unknown,
|
|
|
|
|
/// For expressions that don't emit a value
|
|
|
|
|
None,
|
|
|
|
|
Void,
|
|
|
|
|
Bool,
|
|
|
|
|
Int,
|
|
|
|
|
String,
|
|
|
|
|
Array,
|
|
|
|
|
Fn,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Type {
|
|
|
|
@ -353,9 +475,12 @@ impl fmt::Display for Type {
|
|
|
|
|
"{}",
|
|
|
|
|
match self {
|
|
|
|
|
Type::Unknown => "<unknown>",
|
|
|
|
|
Type::None => "()",
|
|
|
|
|
Type::Void => "()",
|
|
|
|
|
Type::Bool => "bool",
|
|
|
|
|
Type::Int => "int",
|
|
|
|
|
Type::String => "string",
|
|
|
|
|
Type::Array => "array",
|
|
|
|
|
Type::Fn => "fn",
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|