diff --git a/crates/codegen/src/ts.rs b/crates/codegen/src/ts.rs index 756f4dd..4d31b3b 100644 --- a/crates/codegen/src/ts.rs +++ b/crates/codegen/src/ts.rs @@ -31,9 +31,10 @@ impl Codegen { macro_rules! semicolon { () => { if should_gen_semicolon { ";" } else { "" } }; } match ir { - IRKind::Define { name, type_hint, value, mutable } => { + IRKind::Define { public, name, type_hint, value, mutable } => { format!( - "{} v_{}: {} = {}{}\n", + "{} {} v_{}: {} = {}{}\n", + if *public { "export" } else { "" }, if *mutable { "let" } else { "const" }, name, type_hint, @@ -67,14 +68,15 @@ impl Codegen { } }, - IRKind::Fun { name, return_type_hint, args, body } => { + IRKind::Fun { public, name, return_type_hint, args, body } => { let args = args .iter() .map(|arg| format!("v_{}: {}", arg.0, arg.1)) .collect::>(). join(", "); format!( - "const f_{} = ({}): {} => {};\n", + "{} const f_{} = ({}): {} => {};\n", + if *public { "export" } else { "" }, name, args, return_type_hint, @@ -147,4 +149,4 @@ impl Codegen { _ => { dbg!(ir); todo!() }, } } -} \ No newline at end of file +} diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ccc70ed..0757a87 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -14,8 +14,21 @@ pub enum Value { Int(i64), Boolean(bool), String(String), Ident(String) } #[derive(Debug, Clone)] pub enum IRKind { - Define { name: String, type_hint: String, value: Box, mutable: bool }, - Fun { name: String, return_type_hint: String, args: Vec<(String, String)>, body: Box }, + Define { + public: bool, + name: String, + type_hint: String, + value: Box, + mutable: bool + }, + Fun { + public: bool, + name: String, + return_type_hint: String, + args: Vec<(String, String)>, + body: Box + }, + Call { name: String, args: Vec }, Intrinsic { name: String, args: Vec }, Do { body: Vec }, @@ -186,12 +199,13 @@ pub fn expr_to_ir(expr: &Expr) -> (Option, Option) { }; }, - Expr::Let { name, type_hint, value, mutable } => { + Expr::Let { public, name, type_hint, value, mutable } => { let value = expr_to_ir(&value.0); if_err_return!(value.1); let value = value.0.unwrap(); let ir_kind = IRKind::Define { + public: *public, name: name.clone(), type_hint: gen_type_hint(type_hint), value: Box::new(value), @@ -233,7 +247,7 @@ pub fn expr_to_ir(expr: &Expr) -> (Option, Option) { return (Some(ir_kind), None); }, - Expr::Fun { name, type_hint, args, body } => { + Expr::Fun { public, name, type_hint, args, body } => { // Iterate each argument and give it a type hint let args = args.0.iter().map(|arg| (arg.0.0.clone(), gen_type_hint(&arg.1.0))).collect::>(); @@ -241,7 +255,13 @@ pub fn expr_to_ir(expr: &Expr) -> (Option, Option) { if_err_return!(body.1); let body = body.0.unwrap(); - let ir_kind = IRKind::Fun { name: name.clone(), return_type_hint: gen_type_hint(type_hint), args, body: Box::new(body) }; + let ir_kind = IRKind::Fun { + public: *public, + name: name.clone(), + return_type_hint: gen_type_hint(type_hint), + args, + body: Box::new(body) + }; return (Some(ir_kind), None); }, diff --git a/crates/lexer/src/lib.rs b/crates/lexer/src/lib.rs index 4700717..c42ceac 100644 --- a/crates/lexer/src/lib.rs +++ b/crates/lexer/src/lib.rs @@ -8,6 +8,7 @@ pub enum Token { KwIf, KwThen, KwElse, KwCase, KwOf, KwReturn, + KwPub, // Literals Int(i64), Boolean(bool), @@ -42,6 +43,7 @@ impl std::fmt::Display for Token { Token::KwCase => write!(f, "case"), Token::KwOf => write!(f, "of"), Token::KwReturn => write!(f, "return"), + Token::KwPub => write!(f, "pub"), Token::Int(i) => write!(f, "{}", i), Token::Boolean(b) => write!(f, "{}", b), @@ -130,6 +132,7 @@ pub fn lexer() -> impl Parser, Error = Simple> { "case" => Token::KwCase, "of" => Token::KwOf, "return" => Token::KwReturn, + "pub" => Token::KwPub, _ => Token::Identifier(s), }); @@ -181,4 +184,4 @@ mod tests { ])); assert_eq!(err, vec![]); } -} \ No newline at end of file +} diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 7be34d6..9616ce6 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -15,12 +15,14 @@ pub enum Expr { Intrinsic { name: Box>, args: Spanned>> }, Let { + public: bool, name: String, type_hint: String, value: Box>, mutable: bool, }, Fun { + public: bool, name: String, type_hint: String, args: Spanned, Spanned)>>, @@ -198,16 +200,18 @@ fn expr_parser() -> impl Parser>, Error = Simple ) }); - let let_ = just(Token::KwLet) - .ignore_then(just(Token::KwMut).or_not()) + let let_ = just(Token::KwPub).or_not() + .then_ignore(just(Token::KwLet)) + .then(just(Token::KwMut).or_not()) .then(identifier) .then_ignore(just(Token::Colon)) .then(identifier) .then_ignore(just(Token::Assign)) .then(expr.clone()) - .map(|(((mutable, name), type_hint), value)| { + .map(|((((public, mutable), name), type_hint), value)| { ( Expr::Let { + public: public.is_some(), name: name.0.clone(), type_hint: type_hint.0, value: Box::new(value.clone()), @@ -217,8 +221,9 @@ fn expr_parser() -> impl Parser>, Error = Simple ) }); - let fun = just(Token::KwFun) - .ignore_then(identifier) + let fun = just(Token::KwPub).or_not() + .then_ignore(just(Token::KwFun)) + .then(identifier) .then( identifier .then_ignore(just(Token::Colon)) @@ -233,9 +238,10 @@ fn expr_parser() -> impl Parser>, Error = Simple .then(identifier) .then_ignore(just(Token::Assign)) .then(expr.clone()) - .map(|(((name, args), type_hint), body)| { + .map(|((((public, name), args), type_hint), body)| { ( Expr::Fun { + public: public.is_some(), name: name.0.clone(), type_hint: type_hint.0, args: (args, name.1.clone()), @@ -372,4 +378,4 @@ mod tests { assert_eq!(err, vec![]); } -} \ No newline at end of file +} diff --git a/example/export.hz b/example/export.hz new file mode 100644 index 0000000..6dba127 --- /dev/null +++ b/example/export.hz @@ -0,0 +1,4 @@ +pub fun print_something: void = @emit("console.log('something')"); + +fun main: void = do +end;