use std::str::FromStr; use crate::ast; use crate::types; grammar(id_generator: ast::IdGenerator); pub TypeUsage: ast::TypeUsage = { "fn" "(" > ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}), "fn" "(" > ")" ":" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(return_type)), => ast::TypeUsage::Named(ast::NamedTypeUsage{name: name}) }; pub LiteralInt: i64 = { => i64::from_str(literal).unwrap() }; pub SpannedLiteralInt: ast::LiteralInt { > => ast::LiteralInt{value: literal_int, type_: ast::TypeUsage::new_builtin("i64")} }; pub LiteralFloat: f64 = { => f64::from_str(literal).unwrap() }; pub SpannedLiteralInt: ast::LiteralFloat { > => ast::LiteralFloat{value: literal_float, type_: ast::TypeUsage::new_builtin("f64")} }; pub Identifier: String = { => i.to_string() }; pub LiteralStructField: (String, Expression) { ":" => (field, expr) }; pub LiteralStruct: ast::LiteralStruct { "{" > "}" => LiteralStruct{ name: i, fields: field_list.into_iter().collect(), type_: ast::TypeUsage::new_named(i.clone()), } }; pub SpannedIdentifier: ast::Identifier { > => ast::Identifier{name: i} }; pub FunctionCall: ast::FunctionCall = { "(" > ")" => ast::FunctionCall{source: source, arguments: args, type_: ast::TypeUsage::new_unknown(&mut id_generator)} }; pub StructGetter: ast::StructGetter = { "." => ast::StructGetter{source: source, attribute: field, type: ast::TypeUsage::new_unknown(&mut id_generator)} }; pub VariableUsage: ast::VariableUsage = { => ast::VariableUsage{name: identifier, type_: ast::TypeUsage::new_unknown(&mut id_generator)} }; pub Subxpression: Box = { "+" => Box::new(ast::Subexpression::Op(ast::Operation{left: l, op: ast::Operator::Plus, right: r})), "-" => Box::new(ast::Subexpression::Op(ast::Operation{left: l, op: ast::Operator::Minus, right: r})), Factor, }; pub Factor: Box = { "*" => Box::new(ast::Subexpression::Op(ast::Operation{left: l, op: ast::Operator::Mul, right: r})), "/" => Box::new(ast::Subexpression::Op(ast::Operation{left: l, op: ast::Operator::Div, right: r})), Term, }; pub Term: Box = { SpannedLiteralInt => Box::new(ast::Subexpression::LiteralInt(<>)), SpannedLiteralFloat => Box::new(ast::Subexpression::LiteralFloat(<>)), SpannedLiteralStruct => Box::new(ast::Subexpression::LiteralStruct(<>)), FunctionCall => Box::new(ast::Subexpression::FunctionCall(<>)), Identifier => Box::new(ast::Subexpression::Identifier(<>)), "(" ")" => e.subexpression, }; pub Expression: ast::Expression = { => ast::Expression{subexpression: sub, type_: ast::TypeUsage::new_unknown(&mut id_generator)} }; pub ReturnStatement: ast::ReturnStatement = { "return" => ast::ReturnStatement{source: e} }; pub LetStatement: ast::LetStatement = { //TODO: support destructuring with tuples, when they exist. //TODO: add mut, weak "let" "=" => ast::LetStatement{variable_name: n, type_usage: ast::TypeUsage::new_unknown(&mut id_generator), expression: e}, "let" ":" "=" => ast::LetStatement{variable_name: n, type_usage: ast::TypeUsage::Named(ast::NamedTypeUsage{name: t}), expression: e}, }; pub AssignmentStatement: ast::AssignmentStatement { "=" => ast::AssignmentStatement{source: ast::AssignmentTarget::Variable(v), expression: e}, "=" => ast::AssignmentStatement{source: ast::AssignmentTarget::StructAttr(sg), expression: e}, } pub Statement: ast::Statement = { ";" => ast::Statement::Return(r), ";" => ast::Statement::Let(l), ";" => ast::Statement::Assignment(l), ";" => ast::Statement::Expression(e), } pub Block: ast::Block = { "{" "}" => match e { None => ast::Block{statements: s, type_: ast::new_never()}, Some(e) => { let mut v = v; v.push(ast::Statement::Expression(e)); ast::Block{statements: v, type_: ast::TypeUsage::new_unknown(&mut id_generator)} } } } pub TypeUsage: ast::TypeUsage = { => ast::TypeUsage::Named(ast::NamedTypeUsage{name: n}), "fn" "(" > ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::TypeUsage::new_unknown(&mut id_generator))}), "fn" "(" > ")" ":" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(rt)}), } pub VariableDeclaration: ast::VariableDeclaration = { ":" => ast::VariableDeclaration{name: i, type_usage: t}, } pub FunctionDeclaration: ast::FunctionDeclaration { "fn" "(" > ")" => ast::FunctionDeclaration{name: n, arguments: args, return_type: ast::TypeUsage::new_unknown(&mut id_generator)}, "fn" "(" > ")" ":" => ast::FunctionDeclaration{name: n, arguments: args, return_type: rt}, } pub Function: ast::Function = { => ast::Function{declaration: d, block: b} } pub StructField: ast::StructField = { ":" => (i, t), } pub StructTypeDeclaration: ast::StructTypeDeclaration { "type" "struct" "{" Comma "}" } pub TypeAliasDeclaration: ast::TypeAliasDeclaration { "type" "=" ";" => ast::AliasTypeDeclaration{name: i, replaces: t} } pub TypeDeclaration: ast::TypeDeclaration { => ast::TypeDeclaration::Struct(s), => ast::TypeDeclaration::Alias(a), } pub Impl: ast::Impl { "impl" "{" "}" => ast::Impl{struct_name: i, functions: s} } pub ModuleItem: ast::ModuleItem { => ast::ModuleItem::Function(f), => ast::ModuleItem::TypeDeclaration(td), => ast::ModuleItem::Impl(i), } pub Module: ast::Module = { => ast::Module{items: i} } // From https://lalrpop.github.io/lalrpop/tutorial/006_macros.html // Comma seperated list of T with optional trailing comma Comma: Vec = { ",")*> => match e { None => v, Some(e) => { let mut v = v; v.push(e); v } } }; Spanned: ast::Spanned = { => ast::Spanned{span: ast::Span{left: l, right: r}, value: rule} };