diff --git a/src/ast.rs b/src/ast.rs index b5f8e04..1b0fdb6 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -11,9 +11,9 @@ impl IdGenerator { IdGenerator{counter: 0} } - pub fn next(&mut self) -> i64 { + pub fn next(&mut self) -> String { self.counter += 1; - self.counter + ("S" + self.counter.to_string()).to_string() } } @@ -67,7 +67,7 @@ pub struct Spanned { #[derive(Clone, PartialEq, Eq, Hash)] pub struct FunctionTypeUsage { pub arguments: Vec, - pub return_type: TypeUsage, + pub return_type: Box, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -87,6 +87,38 @@ pub enum TypeUsage { Unknown(UnknownTypeUsage), } +impl TypeUsage { + pub fn new_unknown(id_gen: &mut IdGenerator) -> TypeUsage { + return TypeUsage::Unknown(UnknownTypeUsage{ + name: id_gen.next(), + }); + } + + pub fn new_named(identifier: &Identifier) -> TypeUsage { + return TypeUsage::Named(NamedTypeUsage{ + name: identifier.clone(), + }); + } + + pub fn new_builtin(name: String) -> TypeUsage { + ast::TypeUsage::Named(ast::NamedTypeUsage{ + name: ast::Identifier{ + name: ast::Spanned{ + span: ast::Span{left: 0, right: 0}, //todo: figure out a sane value for these + value: name, + } + } + ) + } + + pub fn new_function(arg_count: usize, id_gen: &mut IdGenerator) -> TypeUsage { + return TypeUsage::Function(FunctionTypeUsage{ + arguments: 0..arg_count.map(|_| => TypeUsage.new_unknown(&mut id_gen)).collect(), + return_type: Box::new(TypeUsage.new_unknown(&mut id_gen)), + }); + } +} + #[derive(Clone, PartialEq, Eq, Hash)] pub enum Operator { Mul, @@ -98,19 +130,20 @@ pub enum Operator { #[derive(Clone, PartialEq, Eq, Hash)] pub struct LiteralInt { pub value: Spanned, - pub type: TypeUsage, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] pub struct LiteralFloat { pub value: Spanned, - pub type: TypeUsage, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] pub struct LiteralStruct { + pub name: Identifier, pub fields: HashMap, - pub type: TypeUsage, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -122,14 +155,14 @@ pub struct Identifier { pub struct FunctionCall { pub source: Expression, pub arguments: Vec, - pub type: TypeUsage, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] pub struct StructGetter { - pub source: Box, + pub source: Expression, pub attribute: Identifier, - pub type: TypeUsage, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -137,18 +170,20 @@ pub struct Operation { pub left: Expression, pub op: Operator, pub right: Expression, - pub type: TypeUsage, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] pub struct VariableUsage { pub name: Identifier, - pub type: TypeUsage, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] pub enum Subexpression { LiteralInt(LiteralInt), + LiteralFloat(LiteralFloat), + LiteralStruct(LiteralStruct), FunctionCall(FunctionCall), Identifier(Identifier), Op(Operation), @@ -157,20 +192,19 @@ pub enum Subexpression { #[derive(Clone, PartialEq, Eq, Hash)] pub struct Expression { pub subexpression: Spanned>, - pub type: TypeUsage, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] pub struct ReturnStatement { pub source: Expression, - pub type: TypeUsage, -} +}; #[derive(Clone, PartialEq, Eq, Hash)] pub struct LetStatement { variable_name: Identifier, - type: VariableUsage, expression: Expression, + type_: TypeUsage, } pub enum AssignmentTarget { @@ -182,25 +216,26 @@ pub enum AssignmentTarget { pub struct AssignmentStatement { pub source: AssignmentTarget, pub expression: Expression, - pub type: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] pub enum Statement { - Assignment(Assignment), + Return(ReturnStatement), + Let(LetStatement), + Assignment(AssignmentStatement), Expression(Expression), } #[derive(Clone, PartialEq, Eq, Hash)] pub struct Block { - pub statements: Vec>, - pub type: TypeUsage, + pub statements: Vec, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] pub struct VariableDeclaration { pub name: Identifier, - pub type: TypeUsage, + pub type_: TypeUsage, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -221,10 +256,16 @@ pub struct PrimitiveTypeDeclaration { pub name: String, // cannot be identifier as it's not declared anywhere specific, it's builtins } +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct StructField { + pub name: Identifier, + pub type_: TypeUsage, +} + #[derive(Clone, PartialEq, Eq, Hash)] pub struct StructTypeDeclaration { pub name: Identifier, - pub fields: HashMap, + pub fields: Vec, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -241,14 +282,19 @@ pub enum TypeDeclaration { } #[derive(Clone, PartialEq, Eq, Hash)] -pub enum Impl { +pub struct Impl { pub struct_name: Identifier, pub functions: Vec, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct Module { - pub functions: Vec, - pub types: Vec, - pub impls: Vec, +pub enum ModuleItem { + Function(Function), + TypeDeclaration(TypeDeclaration), + Impl(Impl), +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Module { + pub items: Vec, } diff --git a/src/grammar.lalrpop b/src/grammar.lalrpop index 1207f13..fcc650c 100644 --- a/src/grammar.lalrpop +++ b/src/grammar.lalrpop @@ -6,9 +6,9 @@ grammar(id_generator: ast::IdGenerator); pub TypeUsage: ast::TypeUsage = { - "fn" "(" > ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: ast::new_unit()}), - "fn" "(" > ")" ":" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: return_type), - => ast::TypeUsage::Named(ast::NamedTypeUsage{name: name}) + "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}) }; @@ -17,7 +17,7 @@ pub LiteralInt: i64 = { }; pub SpannedLiteralInt: ast::LiteralInt { - > => ast::LiteralInt{value: literal_int, type: ast::new_named("i64")}, + > => ast::LiteralInt{value: literal_int, type_: ast::TypeUsage::new_builtin("i64")} }; pub LiteralFloat: f64 = { @@ -25,70 +25,150 @@ pub LiteralFloat: f64 = { }; pub SpannedLiteralInt: ast::LiteralFloat { - > => ast::LiteralFloat{value: literal_float, type: ast::new_named("f64")}, + > => ast::LiteralFloat{value: literal_float, type_: ast::TypeUsage::new_builtin("f64")} }; -pub Identifier: ast::Identifier = { - => ast::Identifier{name: i.to_string()} +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{name:i, arguments: args} -} + "(" > ")" => ast::FunctionCall{source: source, arguments: args, type_: ast::TypeUsage::new_unknown(&mut id_generator)} +}; -pub Expression: Box = { - > "+" > => Box::new(ast::Expression::Op(ast::Operation{left: l, op: ast::Operator::Plus, right: r})), - > "-" > => Box::new(ast::Expression::Op(ast::Operation{left: l, op: ast::Operator::Minus, right: r})), +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::Expression::Op(ast::Operation{left: l, op: ast::Operator::Mul, right: r})), - > "/" > => Box::new(ast::Expression::Op(ast::Operation{left: l, op: ast::Operator::Div, right: r})), +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 = { - Spanned => Box::new(ast::Expression::LiteralInt(<>)), - Spanned => Box::new(ast::Expression::Identifier(<>)), - Spanned => Box::new(ast::Expression::FunctionCall(<>)), - "(" ")" => e -} +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 LetStatement: ast::Assignment = { +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::Assignment{name: n, type_usage: None, expression: e}, - "let" > ":" > "=" > => ast::Assignment{name: n, type_usage: Some(t), expression: e}, + "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::Assignment(l), - > => ast::Statement::Expression(e), + ";" => ast::Statement::Return(r), + ";" => ast::Statement::Let(l), + ";" => ast::Statement::Assignment(l), + ";" => ast::Statement::Expression(e), } pub Block: ast::Block = { - "{" >> "}" => ast::Block{statements: s} + "{" "}" => 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{name: n, ty: types::SpecifiedType::Unknown} + => 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}, + ":" => 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 = { - "fn" > "(" > ")" > => ast::Function{name: n, arguments: args, block: b, return_type: rt} + => 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{functions: fs} + => 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 = { @@ -102,16 +182,6 @@ Comma: Vec = { } }; - -LineDelimiter: Vec = { - r"\n|;")*> => { - let mut v = v; - v.push(e); - v - } -}; - - Spanned: ast::Spanned = { => ast::Spanned{span: ast::Span{left: l, right: r}, value: rule} };