use crate::ast; grammar(id_generator: &ast::IdGenerator); match { r"[0-9]+", r"[0-9]+\.[0-9]+", r"[A-Za-z_][A-Za-z0-9_]*", ":", ";", "{", "}", "(", ")", ".", "+", "-", "*", "/", "fn", "return", "let", "true", "false", "if", "else", "=", "for", "type", "trait", "struct", "impl", ",", r"\s*" => { }, r"//[^\n\r]*[\n\r]*" => { }, // `// comment` } pub LiteralInt: String = { => literal.to_string() }; pub SpannedLiteralInt: ast::LiteralInt = { > => ast::LiteralInt{value: literal_int, type_: ast::TypeUsage::new_builtin("i64".to_string())} }; pub LiteralFloat: String = { => literal.to_string() }; pub SpannedLiteralFloat: ast::LiteralFloat = { > => ast::LiteralFloat{value: literal_float, type_: ast::TypeUsage::new_builtin("f64".to_string())} }; pub LiteralBool: String = { "true" => "true".to_string(), "false" => "false".to_string(), }; pub SpannedLiteralBool: ast::LiteralBool = { > => ast::LiteralBool{value: literal_bool, type_: ast::TypeUsage::new_builtin("bool".to_string())} }; pub Identifier: String = { => i.to_string() }; pub LiteralStructField: (ast::Identifier, ast::Expression) = { ":" => (field, expr) }; pub LiteralStruct: ast::LiteralStruct = { "{" > "}" => ast::LiteralStruct{ name: i.clone(), fields: field_list, 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(&id_generator)} }; pub StructGetter: ast::StructGetter = { "." => ast::StructGetter{source: source, attribute: field, type_: ast::TypeUsage::new_unknown(&id_generator)} }; pub VariableUsage: ast::VariableUsage = { => ast::VariableUsage{name: identifier, type_: ast::TypeUsage::new_unknown(&id_generator)} }; pub IfExpression: ast::IfExpression = { "if" "("")" => ast::IfExpression{condition: c, block: b, else_: None, type_: ast::TypeUsage::new_unknown(&id_generator)}, "if" "("")" "else" => ast::IfExpression{condition: c, block: b, else_: Some(e), type_: ast::TypeUsage::new_unknown(&id_generator)}, }; pub Expression: ast::Expression = { "+" => { ast::Expression{ subexpression: Box::new(ast::Subexpression::Op(ast::Operation{left: l, op: ast::Operator::Plus, right: r})), type_: ast::TypeUsage::new_unknown(&id_generator), } }, "-" => { ast::Expression{ subexpression: Box::new(ast::Subexpression::Op(ast::Operation{left: l, op: ast::Operator::Minus, right: r})), type_: ast::TypeUsage::new_unknown(&id_generator), } }, Factor, }; pub Factor: ast::Expression = { "*" => { ast::Expression{ subexpression: Box::new(ast::Subexpression::Op(ast::Operation{left: l, op: ast::Operator::Mul, right: r})), type_: ast::TypeUsage::new_unknown(&id_generator), } }, "/" => { ast::Expression{ subexpression: Box::new(ast::Subexpression::Op(ast::Operation{left: l, op: ast::Operator::Div, right: r})), type_: ast::TypeUsage::new_unknown(&id_generator), } }, Term, }; pub Term: ast::Expression = { SpannedLiteralInt => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralInt(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, SpannedLiteralFloat => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralFloat(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, SpannedLiteralBool => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralBool(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, LiteralStruct => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralStruct(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, FunctionCall => ast::Expression{subexpression: Box::new(ast::Subexpression::FunctionCall(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, StructGetter => ast::Expression{subexpression: Box::new(ast::Subexpression::StructGetter(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, VariableUsage => ast::Expression{subexpression: Box::new(ast::Subexpression::VariableUsage(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, IfExpression => ast::Expression{subexpression: Box::new(ast::Subexpression::If(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, Block => ast::Expression{subexpression: Box::new(ast::Subexpression::Block(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, "(" ")" => e, }; 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_: ast::TypeUsage::new_unknown(&id_generator), expression: e}, "let" ":" "=" => ast::LetStatement{variable_name: n, type_: 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(a), ";" => ast::Statement::Expression(e), }; pub Block: ast::Block = { "{" )*> "}" => match e { None => ast::Block{statements: v, type_: ast::TypeUsage::new_unknown(&id_generator)}, Some(e) => { let mut v = v; v.push(ast::Statement::Expression(e)); ast::Block{statements: v, type_: ast::TypeUsage::new_unknown(&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::new_unit())}), "fn" "(" > ")" ":" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(rt)}), }; pub VariableDeclaration: ast::VariableDeclaration = { ":" => ast::VariableDeclaration{name: i, type_: t}, }; pub FunctionDeclaration: ast::FunctionDeclaration = { "fn" "(" > ")" => ast::FunctionDeclaration{name: n, arguments: args, return_type: ast::new_unit()}, "fn" "(" > ")" ":" => ast::FunctionDeclaration{name: n, arguments: args, return_type: rt}, }; pub Function: ast::Function = { => ast::Function{declaration: d, block: b} }; pub StructField: ast::StructField = { ":" => ast::StructField{name: i, type_: t}, }; pub StructTypeDeclaration: ast::StructTypeDeclaration = { "type" "struct" "{" > "}" => ast::StructTypeDeclaration{name: i, fields: f} }; pub AliasTypeDeclaration: ast::AliasTypeDeclaration = { "type" "=" ";" => ast::AliasTypeDeclaration{name: i, replaces: t} }; pub TraitItem: ast::TraitItem = { ";" => ast::TraitItem::FunctionDeclaration(fd), => ast::TraitItem::Function(f), }; pub TraitTypeDeclaration: ast::TraitTypeDeclaration = { "type" "trait" "{" "}" => ast::TraitTypeDeclaration{name: i, functions: ti}, }; pub TypeDeclaration: ast::TypeDeclaration = { => ast::TypeDeclaration::Struct(s), => ast::TypeDeclaration::Alias(a), => ast::TypeDeclaration::Trait(t), }; pub Impl: ast::Impl = { "impl" "{" "}" => ast::Impl{trait_: None, struct_name: i, functions: f}, "impl" "for" "{" "}" => ast::Impl{trait_: Some(t), struct_name: i, functions: f}, }; 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} };