From 666946032698a3e0308d24ec8606282da93f6348 Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Wed, 10 Aug 2022 22:49:04 -0500 Subject: [PATCH] Parse all namespaced identifiers --- axc/foo.axs | 55 ++++++++++++++++++++---- axc/src/parser.rs | 105 +++++++++++++++++++++++++++++++++------------- axc/src/syntax.rs | 23 +++++++--- 3 files changed, 141 insertions(+), 42 deletions(-) diff --git a/axc/foo.axs b/axc/foo.axs index 24d6fba..76ae887 100644 --- a/axc/foo.axs +++ b/axc/foo.axs @@ -1,8 +1,49 @@ -// AlexScript -def double x = x * 2; -def tuple = (atan2 x y + z, thing); +// AlexScript test -def unary = -2; -def minus = 2 - 2; -def unary_app = 2 (- 2); -def unary_double = 2 - - 2; +extern def core::intrinsic::negate_u32 : U32 -> U32; +extern def core::intrinsic::pow_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::mul_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::div_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::mod_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::plus_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::minus_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::equal_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::notEqual_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::lessThan_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::lessThanEq_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::greaterThan_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::greaterThanEq_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::and_u32 : U32 -> U32 -> U32; +extern def core::intrinsic::or_u32 : U32 -> U32 -> U32; + +extern data U32; + +class Group n { + def plus : n -> n -> n; + def zero : n; + def negate : n -> n; +} + +class Group n => Ring n { + def mul : n -> n -> n; + def one : n; +} + +instance Group U32 { + def plus = core::intrinsic::plus_u32; + def zero = 0; + def negate = core::intrinsic::negate_u32; +} + +instance Ring U32 { + def mul = core::intrinsics::mul_u32; + def one = 1; +} + +extern def print_u32 : U32 -> (); + +// Impurity expliot to chain together actions. +def progn (l: ()) (r: ()) : () = (); + +def main : () = + print_u32 (2 + 2); diff --git a/axc/src/parser.rs b/axc/src/parser.rs index 7c77063..b91ce00 100644 --- a/axc/src/parser.rs +++ b/axc/src/parser.rs @@ -10,7 +10,7 @@ use chumsky::{ }; use crate::syntax::{ - ClassMember, Expr, Literal, Pattern, Statement, SyntaxTree, Type, TypeConstructor, + ClassMember, Expr, Identifier, Literal, Pattern, Statement, SyntaxTree, Type, TypeConstructor, }; /// Adapter to make `chumsky`'s parser errors usable as standard Rust errors. @@ -50,6 +50,9 @@ struct OperatorDef { /// The associativity; if this is Left, then a X b X c is (a X b) X c; for Right, it is a X (b X /// c); for None, it is a syntax error. assoc: Option, + + /// Function call that the binary operator gets translated to. + translation: String, } /// The possible associativity directions of an operator. @@ -70,11 +73,13 @@ impl Default for ParserMeta { name: "^".to_string(), precedence: 8, assoc: Some(Right), + translation: "pow".to_string(), }, OperatorDef { name: "*".to_string(), precedence: 7, assoc: Some(Left), + translation: "mul".to_string(), }, OperatorDef { // Division, which always returns an exact result and does not round to an @@ -82,131 +87,146 @@ impl Default for ParserMeta { name: "/".to_string(), precedence: 7, assoc: Some(Left), + translation: "div".to_string(), }, OperatorDef { // Modulo, defined as Euclidean remainder. name: "%".to_string(), precedence: 7, assoc: Some(Left), + translation: "mod".to_string(), }, OperatorDef { name: "+".to_string(), precedence: 6, assoc: Some(Left), + translation: "plus".to_string(), }, OperatorDef { name: "-".to_string(), precedence: 6, assoc: Some(Left), - }, - OperatorDef { - // Append to head of list. This might get removed since it's inefficient, - // depending. - name: "::".to_string(), - precedence: 5, - assoc: Some(Right), + translation: "minus".to_string(), }, OperatorDef { // Append lists. name: "++".to_string(), precedence: 5, assoc: Some(Right), + translation: "append".to_string(), }, OperatorDef { name: "==".to_string(), precedence: 4, assoc: None, + translation: "equal".to_string(), }, OperatorDef { name: "!=".to_string(), precedence: 4, assoc: None, + translation: "notEqual".to_string(), }, OperatorDef { name: "<".to_string(), precedence: 4, assoc: None, + translation: "lessThan".to_string(), }, OperatorDef { name: "<=".to_string(), precedence: 4, assoc: None, + translation: "lessThanEq".to_string(), }, OperatorDef { name: ">".to_string(), precedence: 4, assoc: None, + translation: "greaterThan".to_string(), }, OperatorDef { name: ">=".to_string(), precedence: 4, assoc: None, + translation: "greaterThanEq".to_string(), }, OperatorDef { // Functor map. name: "<$>".to_string(), precedence: 4, assoc: Some(Left), + translation: "fmap".to_string(), }, OperatorDef { // Functor map to constant. name: "<$".to_string(), precedence: 4, assoc: Some(Left), + translation: "fmapConst".to_string(), }, OperatorDef { // Flipped `<$`. name: "$>".to_string(), precedence: 4, assoc: Some(Left), + translation: "fmapConstFlip".to_string(), }, OperatorDef { // Sequential application of applicative actions. name: "<*>".to_string(), precedence: 4, assoc: Some(Left), + translation: "seqApp".to_string(), }, OperatorDef { // Sequence applicative actions, discarding the left value. name: "*>".to_string(), precedence: 4, assoc: Some(Left), + translation: "seqAppRight".to_string(), }, OperatorDef { // Sequence applicative actions, discarding the right value. name: "<*".to_string(), precedence: 4, assoc: Some(Left), + translation: "seqAppLeft".to_string(), }, OperatorDef { // Binary and boolean `and`. name: "&".to_string(), precedence: 3, assoc: Some(Right), + translation: "and".to_string(), }, OperatorDef { // Binary and boolean `or`. name: "|".to_string(), precedence: 2, assoc: Some(Right), + translation: "or".to_string(), }, OperatorDef { // Monad sequence. name: ">>".to_string(), precedence: 1, assoc: Some(Left), + translation: "monadSeq".to_string(), }, OperatorDef { // Monad bind. name: ">>=".to_string(), precedence: 1, assoc: Some(Left), + translation: "monadBind".to_string(), }, OperatorDef { // Function application. name: "$".to_string(), precedence: 1, assoc: Some(Left), + translation: "apply".to_string(), }, ], } @@ -272,7 +292,7 @@ fn parse_instance_def<'a>( m: &'a ParserMeta, ) -> impl Parser> + 'a { pad(keyword("instance")) - .ignore_then(pad(ident())) + .ignore_then(parse_identifier(m)) .then(parse_type(m)) .then( parse_class_member(m) @@ -302,7 +322,7 @@ fn parse_func_decl<'a>( m: &'a ParserMeta, ) -> impl Parser> + 'a { pad(keyword("def")) - .ignore_then(pad(ident())) + .ignore_then(parse_identifier(m)) .then(parse_pattern(m).repeated()) .then(pad(just('=')).ignore_then(parse_expression(m)).or_not()) .then_ignore(pad(just(';'))) @@ -325,7 +345,7 @@ fn parse_class_def<'a>( m: &'a ParserMeta, ) -> impl Parser> + 'a { pad(keyword("class")) - .ignore_then(pad(ident())) + .ignore_then(parse_identifier(m)) .then(pad(ident())) .then( parse_class_member(m) @@ -382,6 +402,7 @@ fn parse_unary( ops.into_iter().fold(exp, |exp, op| Expr::UnaryOp { kind: op.to_string(), val: Box::new(exp), + translation: "negate".to_string(), }) }) } @@ -395,7 +416,7 @@ fn parse_binary<'a>( let op_parsers = op_defs.map(|def| { pad(just(def.name.to_string())) .ignore_then(base.clone()) - .map(|e| (&def.name, &def.assoc, e)) + .map(|e| (&def.name, &def.assoc, &def.translation, e)) }); let zero = one_of([]).map(|_| unreachable!()).boxed(); @@ -403,7 +424,7 @@ fn parse_binary<'a>( let ops = any_op.repeated(); base.then(ops).map(|(first, others)| { - let mut assocs = others.iter().map(|(_, assoc, _)| assoc); + let mut assocs = others.iter().map(|(_, assoc, _, _)| assoc); let first_assoc = assocs.next(); if !first_assoc.map_or(true, |first| assocs.all(|a| a == first)) { // TODO: Crash the parser properly here, with error recovery etc. @@ -420,10 +441,13 @@ fn parse_binary<'a>( None | Some(Associativity::Left) => { others .into_iter() - .fold(first, |left, (op_name, _assoc, right)| Expr::BinaryOp { - kind: op_name.to_owned(), - left: Box::new(left), - right: Box::new(right), + .fold(first, |left, (op_name, _assoc, translation, right)| { + Expr::BinaryOp { + kind: op_name.to_owned(), + left: Box::new(left), + right: Box::new(right), + translation: translation.to_string(), + } }) } Some(Associativity::Right) => { @@ -443,23 +467,32 @@ fn parse_binary<'a>( // . last // others_l let others_l = std::iter::once(&first) - .chain(others.iter().map(|(_name, _assoc, expr)| expr)) - .zip(others.iter().map(|(name, _assoc, _expr)| name)) + .chain( + others + .iter() + .map(|(_name, _assoc, _translation, expr)| expr), + ) + .zip( + others + .iter() + .map(|(name, _assoc, trans, _expr)| (name, trans)), + ) .collect::>(); let last = others .iter() .last() - .map(|(_name, _assoc, expr)| expr) + .map(|(_name, _assoc, _translation, expr)| expr) .unwrap_or(&first); // And then we can fold as with left-associative operators. others_l .into_iter() .rev() - .fold(last.to_owned(), |r, (l, op)| Expr::BinaryOp { + .fold(last.to_owned(), |r, (l, (op, trans))| Expr::BinaryOp { kind: op.to_string(), left: Box::new(l.to_owned()), right: Box::new(r), + translation: trans.to_string(), }) } } @@ -546,8 +579,7 @@ fn parse_subscript_expr( pad(just('.')) .ignore_then(base) .map(|e| (SubscriptKind::Dot, e)), - rec - .delimited_by(pad(just('[')), pad(just(']'))) + rec.delimited_by(pad(just('[')), pad(just(']'))) .map(|e| (SubscriptKind::Bracket, e)), )) .repeated(), @@ -581,11 +613,8 @@ fn parse_tuple_expr( }) } -fn parse_var_ref_expr(_m: &ParserMeta) -> impl Parser> + Clone { - pad(ident()) - .separated_by(pad(just("::"))) - .at_least(1) - .map(Expr::VariableReference) +fn parse_var_ref_expr(m: &ParserMeta) -> impl Parser> + Clone { + parse_identifier(m).map(Expr::VariableReference) } fn parse_literal(_m: &ParserMeta) -> impl Parser> + Clone { @@ -633,6 +662,15 @@ fn parse_literal(_m: &ParserMeta) -> impl Parser impl Parser> + Clone { + pad(ident()) + .separated_by(pad(just("::"))) + .at_least(1) + .map(|elems| Identifier { elems }) +} + fn parse_type(m: &ParserMeta) -> impl Parser> { recursive(|rec| { choice(( @@ -654,8 +692,8 @@ fn parse_type(m: &ParserMeta) -> impl Parser> { }) } -fn parse_named_type(_m: &ParserMeta) -> impl Parser> { - pad(ident()).map(Type::Named) +fn parse_named_type(m: &ParserMeta) -> impl Parser> { + parse_identifier(m).map(Type::Named) } fn parse_tuple_type( @@ -861,6 +899,13 @@ mod tests { .is_ok()) } + #[test] + fn multi_char_binary() { + assert!(parser(&ParserMeta::default()) + .parse("def x = 2 >= 3;") + .is_ok()) + } + #[test] fn app() { assert!(parser(&ParserMeta::default()) diff --git a/axc/src/syntax.rs b/axc/src/syntax.rs index cc3bf2a..0c0965d 100644 --- a/axc/src/syntax.rs +++ b/axc/src/syntax.rs @@ -23,7 +23,7 @@ pub enum Statement { /// Declaration that a type implements a type class. InstanceDefinition { /// The name of the type class. - class_name: String, + class_name: Identifier, /// The type that conforms to the type class. typ: Type, @@ -36,7 +36,7 @@ pub enum Statement { /// Declaration of a type class. ClassDefinition { /// The name of the class. - name: String, + name: Identifier, /// The type variable representing a type conforming to the class. var: String, @@ -58,7 +58,7 @@ pub enum ClassMember { /// Declaration of a function or constant. Function { /// Name of the function. - name: String, + name: Identifier, /// The function arguments. arguments: Vec, @@ -97,6 +97,9 @@ pub enum Expr { /// The value being operated upon. val: Box, + + /// The function that the unary operator translates to. + translation: String, }, /// Binary operators, e.g., `5 + 5`. @@ -109,6 +112,9 @@ pub enum Expr { /// The right side of the operator. right: Box, + + /// The function that the binary operator translates to. + translation: String, }, /// Function application, e.g., `sin x`. @@ -177,7 +183,7 @@ pub enum Expr { Tuple(Vec), /// Variable references, possibly namespaced, e.g., `foo::bar::baz`. - VariableReference(Vec), + VariableReference(Identifier), /// Literal tokens, e.g., strings and numbers. Literal(Literal), @@ -187,7 +193,7 @@ pub enum Expr { #[derive(Clone, Debug)] pub enum Type { /// `Foo` - Named(String), + Named(Identifier), /// `List Int` Application { @@ -245,6 +251,13 @@ pub enum Pattern { Literal(Literal), } +/// Namespaced identifiers. +#[derive(Clone, Debug)] +pub struct Identifier { + /// The elements of the identifier; there must be at least one of these. + pub elems: Vec, +} + /// Literal values included in source code. #[derive(Clone, Debug)] pub enum Literal {