M src/ast.rs +7 -0
@@ 27,12 27,14 @@ impl From<&str> for Type {
}
}
+/// A parameter for a function.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Param {
pub name: String,
pub typ: Type,
}
+/// A function declaration.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct FunctionDecl {
pub name: String,
@@ 41,12 43,14 @@ pub struct FunctionDecl {
pub body: Vec<Expr>,
}
+/// A structure declaration
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StructureDecl {
pub name: String,
pub fields: Vec<(String, Type)>,
}
+/// A declaration of some kind or another
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Decl {
/// Function definition
@@ 55,6 59,7 @@ pub enum Decl {
Structure(StructureDecl),
}
+/// A literal value.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, PartialOrd)]
pub enum Lit {
F32(f32),
@@ 159,6 164,8 @@ pub enum Pattern {
pub type Exprs = Vec<Expr>;
/// Expression that returns a value.
+///
+/// TODO: All of these need a span of some kind in the thing.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Expr {
/// Unary operation
M src/compile/mod.rs +19 -7
@@ 98,9 98,11 @@ impl CContext {
}
/// Binds the variable to the current scope.
- /// Will overwrite any previous binding. That's fine.
+ /// Will overwrite any previous binding in this scope. That's fine,
+ /// since there's no way to refer to a shadowed variable.
///
- /// Panics if no scope.
+ /// # Panics
+ /// Panics if no scope exists
pub fn bind_var(&mut self, name: &str, address: spirv::Word, typedef: spirv::Word) {
self.symtable
.last_mut()
@@ 108,8 110,13 @@ impl CContext {
.insert(name.into(), VarBinding { address, typedef });
}
- /// Returns the Word bound to the given var name, or panics if not found.
- /// All unknown vars should get caught by the validation step.
+ /// Returns the Word bound to the given var name
+ ///
+ /// # Panics
+ /// Panics if no scope exists.
+ ///
+ /// Panics if var name is not bound; all unknown vars should
+ /// get caught by the validation step.
pub fn lookup_var(&self, name: &str) -> &VarBinding {
assert!(!self.symtable.is_empty(), "No scope for variable lookup!");
for scope in self.symtable.iter().rev() {
@@ 177,9 184,14 @@ impl CContext {
}
}
- /// Panics if the type does not exist.
+ /// Gets the type with the given definition.
///
/// TODO: Should this take a name and a VContext instead of a TypeDef?
+ /// mmmmmmmaybe. Probably. We probably do want name equality rather
+ /// than structural equality.
+ ///
+ /// # Panics
+ /// Panics if the type does not exist.
pub fn get_type(&self, t: &verify::TypeDef) -> spirv::Word {
*self.typetable.get(t).expect("Could not get type!")
}
@@ 276,8 288,8 @@ impl CContext {
}
}
- /// Returns the two Word's, the first holding the result of the expression,
- /// the second holdin its type.
+ /// Returns two Word's, the first holding the result of the expression,
+ /// the second holding its type.
pub fn compile_expr(
&mut self,
e: &ast::Expr,
M src/lib.rs +20 -1
@@ 1,4 1,5 @@
use std::borrow::Cow;
+use std::fmt;
use pest;
use pest_derive::Parser;
@@ 32,6 33,21 @@ impl From<rspirv::mr::Error> for Error {
}
}
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Error::TypeMismatch(t1, t2) => {
+ write!(f, "Type mismatch: expected {:?}, got {:?}", t1, t2)
+ }
+ Error::Validation(v) => write!(f, "Validation failed: {}", v),
+ Error::SymbolExists(s) => write!(f, "Tried to redefine symbol: {}", s),
+ Error::CodegenError => write!(f, "Miscellanious codegen error of some kind"),
+ }
+ }
+}
+
+impl std::error::Error for Error {}
+
/// TODO: Parser.
pub fn parse(input: &str) -> Vec<ast::Decl> {
use pest::Parser;
@@ 39,7 55,7 @@ pub fn parse(input: &str) -> Vec<ast::De
for pair in parser {
println!("Pair: {:?}", pair);
}
- vec![]
+ unimplemented!("No parser yet")
}
/// Well, SPIR-V is defined to be a list of u32 words, but its byte order is undefined,
@@ 50,6 66,7 @@ pub fn parse(input: &str) -> Vec<ast::De
/// We COULD use unsafe to just cast the `&[u32]` to `&[u8]`, but that would be lame
/// and platform-specific, so we do it RIGHT, copying the buffer in the process.
/// Fite me.
+/// TODO: The `bytemuck` crate might make this better?
pub fn words_to_bytes_le(words: &[u32]) -> Vec<u8> {
/* Iterating over the [u8;4]'s is *problematic*,
all the solutions I can come up with borrow it first
@@ 74,6 91,7 @@ pub fn compile(input: &str) -> Vec<u32>
#[cfg(test)]
mod tests {
+ /*
use super::*;
use pest::Parser;
@@ 82,4 100,5 @@ mod tests {
let input = "hello world";
let _pairs = ChParser::parse(Rule::ident, input).unwrap();
}
+ */
}
M src/verify.rs +10 -0
@@ 64,16 64,26 @@ use crate::Error;
/// has a particular type for vectors. Hmm, for now
/// let's just treat them as structs, it might change
/// later.
+///
+/// The trick to vectors is really the layout, and
+/// the swizzling operators. Both of these kiiiinda
+/// matter. So we can either special case vectors
+/// as types, or special case any struct that
+/// could look like a vector. Special casing
+/// vectors seems easier.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum TypeDef {
F32,
Vec4F,
+ //RAR VecN(u8, TypeDef)
Bool,
Unit,
Struct(Vec<(String, TypeDef)>),
Function(Vec<TypeDef>, Box<TypeDef>),
}
+//RAR pub type FunctionType = (Vec<TypeDef>, Box<TypeDef>)
+
/// A function definition; the AST and whatever
/// other information we care about that can get
/// fed to the actual compiler-y bits.