153 lines
4.5 KiB
Rust
153 lines
4.5 KiB
Rust
use std::fmt;
|
|
use std::hash::Hash;
|
|
|
|
use internment::ArcIntern;
|
|
|
|
pub use crate::syntax::tokens::ConstantType;
|
|
use crate::syntax::Location;
|
|
|
|
/// A structure represented a parsed program.
|
|
///
|
|
/// One `Program` is associated with exactly one input file, and the
|
|
/// vector is arranged in exactly the same order as the parsed file.
|
|
/// Because this is the syntax layer, the program is guaranteed to be
|
|
/// syntactically valid, but may be nonsense. There could be attempts
|
|
/// to use unbound variables, for example, until after someone runs
|
|
/// `validate` and it comes back without errors.
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct Program {
|
|
pub statements: Vec<Statement>,
|
|
}
|
|
|
|
/// A Name.
|
|
///
|
|
/// This is basically a string, but annotated with the place the string
|
|
/// is in the source file.
|
|
#[derive(Clone, Debug)]
|
|
pub struct Name {
|
|
pub name: String,
|
|
pub location: Location,
|
|
}
|
|
|
|
impl Name {
|
|
pub fn new<S: ToString>(n: S, location: Location) -> Name {
|
|
Name {
|
|
name: n.to_string(),
|
|
location,
|
|
}
|
|
}
|
|
|
|
pub fn manufactured<S: ToString>(n: S) -> Name {
|
|
Name {
|
|
name: n.to_string(),
|
|
location: Location::manufactured(),
|
|
}
|
|
}
|
|
|
|
pub fn intern(self) -> ArcIntern<String> {
|
|
ArcIntern::new(self.name)
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Name {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.name == other.name
|
|
}
|
|
}
|
|
|
|
impl Eq for Name {}
|
|
|
|
impl Hash for Name {
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
self.name.hash(state)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Name {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.name.fmt(f)
|
|
}
|
|
}
|
|
|
|
/// A parsed statement.
|
|
///
|
|
/// Statements are guaranteed to be syntactically valid, but may be
|
|
/// complete nonsense at the semantic level. Which is to say, all the
|
|
/// print statements were correctly formatted, and all the variables
|
|
/// referenced are definitely valid symbols, but they may not have
|
|
/// been defined or anything.
|
|
///
|
|
/// Note that equivalence testing on statements is independent of
|
|
/// source location; it is testing if the two statements say the same
|
|
/// thing, not if they are the exact same statement.
|
|
#[derive(Clone, Debug)]
|
|
pub enum Statement {
|
|
Binding(Location, Name, Expression),
|
|
Print(Location, Name),
|
|
}
|
|
|
|
impl PartialEq for Statement {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match self {
|
|
Statement::Binding(_, name1, expr1) => match other {
|
|
Statement::Binding(_, name2, expr2) => name1 == name2 && expr1 == expr2,
|
|
_ => false,
|
|
},
|
|
Statement::Print(_, name1) => match other {
|
|
Statement::Print(_, name2) => name1 == name2,
|
|
_ => false,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An expression in the underlying syntax.
|
|
///
|
|
/// Like statements, these expressions are guaranteed to have been
|
|
/// formatted correctly, but may not actually make any sense. Also
|
|
/// like Statements, the [`PartialEq`] implementation does not take
|
|
/// source positions into account.
|
|
#[derive(Clone, Debug)]
|
|
pub enum Expression {
|
|
Value(Location, Value),
|
|
Reference(Location, String),
|
|
Cast(Location, String, Box<Expression>),
|
|
Primitive(Location, String, Vec<Expression>),
|
|
}
|
|
|
|
impl PartialEq for Expression {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match self {
|
|
Expression::Value(_, val1) => match other {
|
|
Expression::Value(_, val2) => val1 == val2,
|
|
_ => false,
|
|
},
|
|
Expression::Reference(_, var1) => match other {
|
|
Expression::Reference(_, var2) => var1 == var2,
|
|
_ => false,
|
|
},
|
|
Expression::Cast(_, t1, e1) => match other {
|
|
Expression::Cast(_, t2, e2) => t1 == t2 && e1 == e2,
|
|
_ => false,
|
|
},
|
|
Expression::Primitive(_, prim1, args1) => match other {
|
|
Expression::Primitive(_, prim2, args2) => prim1 == prim2 && args1 == args2,
|
|
_ => false,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A value from the source syntax
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub enum Value {
|
|
/// The value of the number, an optional base that it was written in, and any
|
|
/// type information provided.
|
|
///
|
|
/// u64 is chosen because it should be big enough to carry the amount of
|
|
/// information we need, and technically we interpret -4 as the primitive unary
|
|
/// operation "-" on the number 4. We'll translate this into a type-specific
|
|
/// number at a later time.
|
|
Number(Option<u8>, Option<ConstantType>, u64),
|
|
}
|