Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wavec"
version = "0.1.6-pre-beta"
version = "0.1.7-pre-beta"
edition = "2021"

[lib]
Expand Down
31 changes: 31 additions & 0 deletions examples/type_enum.wave
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
type MyInt = i32;

enum ShaderUniformType -> MyInt {
A = 0,
B,
C = 10,
D
}

const X: MyInt = 123;
const Y: MyInt = B;
const Z: ShaderUniformType = D;

fun f(t: ShaderUniformType) -> MyInt {
return t;
}

fun g(v: MyInt) -> MyInt {
return v;
}

fun main() {
println("{}", f(A)); // 0
println("{}", f(B)); // 1
println("{}", f(C)); // 10
println("{}", f(D)); // 11

println("{}", g(X)); // 123
println("{}", g(Y)); // 1
println("{}", f(Z)); // 11
}
10 changes: 10 additions & 0 deletions front/lexer/src/lexer/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ impl<'a> Lexer<'a> {
lexeme: "extern".to_string(),
line: self.line,
},
"type" => Token {
token_type: TokenType::Type,
lexeme: "type".to_string(),
line: self.line,
},
"enum" => Token {
token_type: TokenType::Enum,
lexeme: "enum".to_string(),
line: self.line,
},
"var" => Token {
token_type: TokenType::Var,
lexeme: "var".to_string(),
Expand Down
2 changes: 2 additions & 0 deletions front/lexer/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ impl fmt::Display for UnsignedIntegerType {
pub enum TokenType {
Fun,
Extern,
Type,
Enum,
Var,
Let,
Mut,
Expand Down
24 changes: 22 additions & 2 deletions front/parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,27 @@ pub enum ASTNode {
Expression(Expression),
Struct(StructNode),
ProtoImpl(ProtoImplNode),
TypeAlias(TypeAliasNode),
Enum(EnumNode),
}

#[derive(Debug, Clone)]
pub struct TypeAliasNode {
pub name: String,
pub target: WaveType,
}

#[derive(Debug, Clone)]
pub struct EnumNode {
pub name: String,
pub repr_type: WaveType,
pub variants: Vec<EnumVariantNode>,
}

#[derive(Debug, Clone)]
pub struct EnumVariantNode {
pub name: String,
pub explicit_value: Option<String>,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -259,8 +280,7 @@ pub enum StatementNode {
Expression(Expression),
}

#[derive(Debug, Clone, PartialEq)]
#[derive(Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Mutability {
Var,
Let,
Expand Down
171 changes: 170 additions & 1 deletion front/parser/src/parser/decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::iter::Peekable;
use std::slice::Iter;
use lexer::Token;
use lexer::token::TokenType;
use crate::ast::{ASTNode, Expression, ExternFunctionNode, Mutability, VariableNode, WaveType};
use crate::ast::{ASTNode, EnumNode, EnumVariantNode, Expression, ExternFunctionNode, Mutability, TypeAliasNode, VariableNode, WaveType};
use crate::expr::parse_expression;
use crate::parser::types::{parse_type, token_type_to_wave_type};
use crate::types::parse_type_from_stream;
Expand Down Expand Up @@ -613,4 +613,173 @@ pub fn parse_extern(tokens: &mut Peekable<Iter<'_, Token>>) -> Option<Vec<ASTNod
println!("Error: Expected 'fun' or '{{' after extern(...)");
None
}
}

pub fn parse_type_alias(tokens: &mut Peekable<Iter<'_, Token>>) -> Option<ASTNode> {
// type <Ident> = <Type> ;
let name = match tokens.next() {
Some(Token { token_type: TokenType::Identifier(n), .. }) => n.clone(),
other => {
println!("Error: Expected identifier after 'type', found {:?}", other);
return None;
}
};

match tokens.next() {
Some(Token { token_type: TokenType::Equal, .. }) => {}
other => {
println!("Error: Expected '=' in type alias, found {:?}", other);
return None;
}
}

let target = match parse_type_from_stream(tokens) {
Some(t) => t,
None => {
println!("Error: Expected type after '=' in type alias '{}'", name);
return None;
}
};

match tokens.next() {
Some(Token { token_type: TokenType::SemiColon, .. }) => {}
other => {
println!("Error: Expected ';' after type alias, found {:?}", other);
return None;
}
}

Some(ASTNode::TypeAlias(TypeAliasNode { name, target }))
}

fn token_text(tok: &Token) -> Option<String> {
if !tok.lexeme.is_empty() {
return Some(tok.lexeme.clone());
}
if let TokenType::Identifier(s) = &tok.token_type {
return Some(s.clone());
}
None
}

pub fn parse_enum(tokens: &mut Peekable<Iter<'_, Token>>) -> Option<ASTNode> {
// enum <Ident> -> <Type> { <Variant>(=<Int>)? (, ...)* }
let name = match tokens.next() {
Some(Token { token_type: TokenType::Identifier(n), .. }) => n.clone(),
other => {
println!("Error: Expected enum name after 'enum', found {:?}", other);
return None;
}
};

match tokens.next() {
Some(Token { token_type: TokenType::Arrow, .. }) => {}
other => {
println!("Error: Expected '->' after enum name, found {:?}", other);
return None;
}
}

let repr_type = match parse_type_from_stream(tokens) {
Some(t) => t,
None => {
println!("Error: Expected repr type after '->' in enum '{}'", name);
return None;
}
};

match tokens.next() {
Some(Token { token_type: TokenType::Lbrace, .. }) => {}
other => {
println!("Error: Expected '{{' to start enum body, found {:?}", other);
return None;
}
}

let mut variants: Vec<EnumVariantNode> = Vec::new();

loop {
let next_ty = match tokens.peek() {
Some(t) => t.token_type.clone(),
None => {
println!("Error: Unexpected end of file inside enum '{}'", name);
return None;
}
};

match next_ty {
TokenType::Rbrace => {
tokens.next(); // consume '}'
break;
}
TokenType::Identifier(_) => {
// variant name
let vname = match tokens.next() {
Some(Token { token_type: TokenType::Identifier(n), .. }) => n.clone(),
_ => unreachable!(),
};

// optional '= <value>'
let mut explicit_value: Option<String> = None;
if matches!(tokens.peek().map(|t| &t.token_type), Some(TokenType::Equal)) {
tokens.next(); // consume '='

let val_tok = match tokens.next() {
Some(t) => t,
None => {
println!("Error: Expected integer literal after '=' in enum '{}'", name);
return None;
}
};

let raw = match token_text(val_tok) {
Some(s) => s,
None => {
println!("Error: Expected integer literal after '=' in enum '{}', found {:?}", name, val_tok);
return None;
}
};

explicit_value = Some(raw);
}

variants.push(EnumVariantNode {
name: vname,
explicit_value,
});

// after variant: ',' or '}'
match tokens.peek().map(|t| t.token_type.clone()) {
Some(TokenType::Comma) => {
tokens.next(); // consume ','

continue;
}
Some(TokenType::Rbrace) => {
continue;
}
other => {
println!(
"Error: Expected ',' or '}}' after enum variant in '{}', found {:?}",
name, other
);
return None;
}
}
}
other => {
println!(
"Error: Expected enum variant name or '}}' in '{}', found {:?}",
name, other
);
return None;
}
}
}

Some(ASTNode::Enum(EnumNode {
name,
repr_type,
variants,
}))
}
16 changes: 16 additions & 0 deletions front/parser/src/parser/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ pub fn parse(tokens: &Vec<Token>) -> Option<Vec<ASTNode>> {
return None;
}
}
TokenType::Type => {
iter.next(); // consume 'type'
if let Some(node) = parse_type_alias(&mut iter) {
nodes.push(node);
} else {
return None;
}
}
TokenType::Enum => {
iter.next(); // consume 'enum'
if let Some(node) = parse_enum(&mut iter) {
nodes.push(node);
} else {
return None;
}
}
TokenType::Struct => {
iter.next();
if let Some(struct_node) = parse_struct(&mut iter) {
Expand Down
26 changes: 22 additions & 4 deletions front/parser/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,13 @@ fn validate_expr(
validate_expr(inner, scopes, globals)?;
}

Expression::Literal(_) | Expression::Variable(_) => {}
Expression::Literal(_) => {}

Expression::Variable(name) => {
if lookup_mutability(name, scopes, globals).is_none() {
return Err(format!("use of undeclared identifier `{}`", name));
}
}

_ => {}
}
Expand Down Expand Up @@ -249,11 +255,23 @@ fn validate_node(

pub fn validate_program(nodes: &Vec<ASTNode>) -> Result<(), String> {
let mut globals: HashMap<String, Mutability> = HashMap::new();

for n in nodes {
if let ASTNode::Variable(v) = n {
if v.mutability == Mutability::Const {
globals.insert(v.name.clone(), Mutability::Const);
match n {
ASTNode::Variable(v) => {
if v.mutability == Mutability::Const {
globals.insert(v.name.clone(), Mutability::Const);
}
}

// NEW: enum variants are constants
ASTNode::Enum(e) => {
for v in &e.variants {
globals.insert(v.name.clone(), Mutability::Const);
}
}

_ => {}
}
}

Expand Down
Loading