Parse all namespaced identifiers

This commit is contained in:
Alex Bethel 2022-08-10 22:49:04 -05:00
parent ef0fb0efc2
commit 6669460326
3 changed files with 141 additions and 42 deletions

View file

@ -1,8 +1,49 @@
// AlexScript // AlexScript test
def double x = x * 2;
def tuple = (atan2 x y + z, thing);
def unary = -2; extern def core::intrinsic::negate_u32 : U32 -> U32;
def minus = 2 - 2; extern def core::intrinsic::pow_u32 : U32 -> U32 -> U32;
def unary_app = 2 (- 2); extern def core::intrinsic::mul_u32 : U32 -> U32 -> U32;
def unary_double = 2 - - 2; 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);

View file

@ -10,7 +10,7 @@ use chumsky::{
}; };
use crate::syntax::{ 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. /// 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 /// 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. /// c); for None, it is a syntax error.
assoc: Option<Associativity>, assoc: Option<Associativity>,
/// Function call that the binary operator gets translated to.
translation: String,
} }
/// The possible associativity directions of an operator. /// The possible associativity directions of an operator.
@ -70,11 +73,13 @@ impl Default for ParserMeta {
name: "^".to_string(), name: "^".to_string(),
precedence: 8, precedence: 8,
assoc: Some(Right), assoc: Some(Right),
translation: "pow".to_string(),
}, },
OperatorDef { OperatorDef {
name: "*".to_string(), name: "*".to_string(),
precedence: 7, precedence: 7,
assoc: Some(Left), assoc: Some(Left),
translation: "mul".to_string(),
}, },
OperatorDef { OperatorDef {
// Division, which always returns an exact result and does not round to an // Division, which always returns an exact result and does not round to an
@ -82,131 +87,146 @@ impl Default for ParserMeta {
name: "/".to_string(), name: "/".to_string(),
precedence: 7, precedence: 7,
assoc: Some(Left), assoc: Some(Left),
translation: "div".to_string(),
}, },
OperatorDef { OperatorDef {
// Modulo, defined as Euclidean remainder. // Modulo, defined as Euclidean remainder.
name: "%".to_string(), name: "%".to_string(),
precedence: 7, precedence: 7,
assoc: Some(Left), assoc: Some(Left),
translation: "mod".to_string(),
}, },
OperatorDef { OperatorDef {
name: "+".to_string(), name: "+".to_string(),
precedence: 6, precedence: 6,
assoc: Some(Left), assoc: Some(Left),
translation: "plus".to_string(),
}, },
OperatorDef { OperatorDef {
name: "-".to_string(), name: "-".to_string(),
precedence: 6, precedence: 6,
assoc: Some(Left), assoc: Some(Left),
}, translation: "minus".to_string(),
OperatorDef {
// Append to head of list. This might get removed since it's inefficient,
// depending.
name: "::".to_string(),
precedence: 5,
assoc: Some(Right),
}, },
OperatorDef { OperatorDef {
// Append lists. // Append lists.
name: "++".to_string(), name: "++".to_string(),
precedence: 5, precedence: 5,
assoc: Some(Right), assoc: Some(Right),
translation: "append".to_string(),
}, },
OperatorDef { OperatorDef {
name: "==".to_string(), name: "==".to_string(),
precedence: 4, precedence: 4,
assoc: None, assoc: None,
translation: "equal".to_string(),
}, },
OperatorDef { OperatorDef {
name: "!=".to_string(), name: "!=".to_string(),
precedence: 4, precedence: 4,
assoc: None, assoc: None,
translation: "notEqual".to_string(),
}, },
OperatorDef { OperatorDef {
name: "<".to_string(), name: "<".to_string(),
precedence: 4, precedence: 4,
assoc: None, assoc: None,
translation: "lessThan".to_string(),
}, },
OperatorDef { OperatorDef {
name: "<=".to_string(), name: "<=".to_string(),
precedence: 4, precedence: 4,
assoc: None, assoc: None,
translation: "lessThanEq".to_string(),
}, },
OperatorDef { OperatorDef {
name: ">".to_string(), name: ">".to_string(),
precedence: 4, precedence: 4,
assoc: None, assoc: None,
translation: "greaterThan".to_string(),
}, },
OperatorDef { OperatorDef {
name: ">=".to_string(), name: ">=".to_string(),
precedence: 4, precedence: 4,
assoc: None, assoc: None,
translation: "greaterThanEq".to_string(),
}, },
OperatorDef { OperatorDef {
// Functor map. // Functor map.
name: "<$>".to_string(), name: "<$>".to_string(),
precedence: 4, precedence: 4,
assoc: Some(Left), assoc: Some(Left),
translation: "fmap".to_string(),
}, },
OperatorDef { OperatorDef {
// Functor map to constant. // Functor map to constant.
name: "<$".to_string(), name: "<$".to_string(),
precedence: 4, precedence: 4,
assoc: Some(Left), assoc: Some(Left),
translation: "fmapConst".to_string(),
}, },
OperatorDef { OperatorDef {
// Flipped `<$`. // Flipped `<$`.
name: "$>".to_string(), name: "$>".to_string(),
precedence: 4, precedence: 4,
assoc: Some(Left), assoc: Some(Left),
translation: "fmapConstFlip".to_string(),
}, },
OperatorDef { OperatorDef {
// Sequential application of applicative actions. // Sequential application of applicative actions.
name: "<*>".to_string(), name: "<*>".to_string(),
precedence: 4, precedence: 4,
assoc: Some(Left), assoc: Some(Left),
translation: "seqApp".to_string(),
}, },
OperatorDef { OperatorDef {
// Sequence applicative actions, discarding the left value. // Sequence applicative actions, discarding the left value.
name: "*>".to_string(), name: "*>".to_string(),
precedence: 4, precedence: 4,
assoc: Some(Left), assoc: Some(Left),
translation: "seqAppRight".to_string(),
}, },
OperatorDef { OperatorDef {
// Sequence applicative actions, discarding the right value. // Sequence applicative actions, discarding the right value.
name: "<*".to_string(), name: "<*".to_string(),
precedence: 4, precedence: 4,
assoc: Some(Left), assoc: Some(Left),
translation: "seqAppLeft".to_string(),
}, },
OperatorDef { OperatorDef {
// Binary and boolean `and`. // Binary and boolean `and`.
name: "&".to_string(), name: "&".to_string(),
precedence: 3, precedence: 3,
assoc: Some(Right), assoc: Some(Right),
translation: "and".to_string(),
}, },
OperatorDef { OperatorDef {
// Binary and boolean `or`. // Binary and boolean `or`.
name: "|".to_string(), name: "|".to_string(),
precedence: 2, precedence: 2,
assoc: Some(Right), assoc: Some(Right),
translation: "or".to_string(),
}, },
OperatorDef { OperatorDef {
// Monad sequence. // Monad sequence.
name: ">>".to_string(), name: ">>".to_string(),
precedence: 1, precedence: 1,
assoc: Some(Left), assoc: Some(Left),
translation: "monadSeq".to_string(),
}, },
OperatorDef { OperatorDef {
// Monad bind. // Monad bind.
name: ">>=".to_string(), name: ">>=".to_string(),
precedence: 1, precedence: 1,
assoc: Some(Left), assoc: Some(Left),
translation: "monadBind".to_string(),
}, },
OperatorDef { OperatorDef {
// Function application. // Function application.
name: "$".to_string(), name: "$".to_string(),
precedence: 1, precedence: 1,
assoc: Some(Left), assoc: Some(Left),
translation: "apply".to_string(),
}, },
], ],
} }
@ -272,7 +292,7 @@ fn parse_instance_def<'a>(
m: &'a ParserMeta, m: &'a ParserMeta,
) -> impl Parser<char, Statement, Error = Simple<char>> + 'a { ) -> impl Parser<char, Statement, Error = Simple<char>> + 'a {
pad(keyword("instance")) pad(keyword("instance"))
.ignore_then(pad(ident())) .ignore_then(parse_identifier(m))
.then(parse_type(m)) .then(parse_type(m))
.then( .then(
parse_class_member(m) parse_class_member(m)
@ -302,7 +322,7 @@ fn parse_func_decl<'a>(
m: &'a ParserMeta, m: &'a ParserMeta,
) -> impl Parser<char, ClassMember, Error = Simple<char>> + 'a { ) -> impl Parser<char, ClassMember, Error = Simple<char>> + 'a {
pad(keyword("def")) pad(keyword("def"))
.ignore_then(pad(ident())) .ignore_then(parse_identifier(m))
.then(parse_pattern(m).repeated()) .then(parse_pattern(m).repeated())
.then(pad(just('=')).ignore_then(parse_expression(m)).or_not()) .then(pad(just('=')).ignore_then(parse_expression(m)).or_not())
.then_ignore(pad(just(';'))) .then_ignore(pad(just(';')))
@ -325,7 +345,7 @@ fn parse_class_def<'a>(
m: &'a ParserMeta, m: &'a ParserMeta,
) -> impl Parser<char, Statement, Error = Simple<char>> + 'a { ) -> impl Parser<char, Statement, Error = Simple<char>> + 'a {
pad(keyword("class")) pad(keyword("class"))
.ignore_then(pad(ident())) .ignore_then(parse_identifier(m))
.then(pad(ident())) .then(pad(ident()))
.then( .then(
parse_class_member(m) parse_class_member(m)
@ -382,6 +402,7 @@ fn parse_unary(
ops.into_iter().fold(exp, |exp, op| Expr::UnaryOp { ops.into_iter().fold(exp, |exp, op| Expr::UnaryOp {
kind: op.to_string(), kind: op.to_string(),
val: Box::new(exp), val: Box::new(exp),
translation: "negate".to_string(),
}) })
}) })
} }
@ -395,7 +416,7 @@ fn parse_binary<'a>(
let op_parsers = op_defs.map(|def| { let op_parsers = op_defs.map(|def| {
pad(just(def.name.to_string())) pad(just(def.name.to_string()))
.ignore_then(base.clone()) .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(); let zero = one_of([]).map(|_| unreachable!()).boxed();
@ -403,7 +424,7 @@ fn parse_binary<'a>(
let ops = any_op.repeated(); let ops = any_op.repeated();
base.then(ops).map(|(first, others)| { 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(); let first_assoc = assocs.next();
if !first_assoc.map_or(true, |first| assocs.all(|a| a == first)) { if !first_assoc.map_or(true, |first| assocs.all(|a| a == first)) {
// TODO: Crash the parser properly here, with error recovery etc. // TODO: Crash the parser properly here, with error recovery etc.
@ -420,10 +441,13 @@ fn parse_binary<'a>(
None | Some(Associativity::Left) => { None | Some(Associativity::Left) => {
others others
.into_iter() .into_iter()
.fold(first, |left, (op_name, _assoc, right)| Expr::BinaryOp { .fold(first, |left, (op_name, _assoc, translation, right)| {
kind: op_name.to_owned(), Expr::BinaryOp {
left: Box::new(left), kind: op_name.to_owned(),
right: Box::new(right), left: Box::new(left),
right: Box::new(right),
translation: translation.to_string(),
}
}) })
} }
Some(Associativity::Right) => { Some(Associativity::Right) => {
@ -443,23 +467,32 @@ fn parse_binary<'a>(
// . last // . last
// others_l // others_l
let others_l = std::iter::once(&first) let others_l = std::iter::once(&first)
.chain(others.iter().map(|(_name, _assoc, expr)| expr)) .chain(
.zip(others.iter().map(|(name, _assoc, _expr)| name)) others
.iter()
.map(|(_name, _assoc, _translation, expr)| expr),
)
.zip(
others
.iter()
.map(|(name, _assoc, trans, _expr)| (name, trans)),
)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let last = others let last = others
.iter() .iter()
.last() .last()
.map(|(_name, _assoc, expr)| expr) .map(|(_name, _assoc, _translation, expr)| expr)
.unwrap_or(&first); .unwrap_or(&first);
// And then we can fold as with left-associative operators. // And then we can fold as with left-associative operators.
others_l others_l
.into_iter() .into_iter()
.rev() .rev()
.fold(last.to_owned(), |r, (l, op)| Expr::BinaryOp { .fold(last.to_owned(), |r, (l, (op, trans))| Expr::BinaryOp {
kind: op.to_string(), kind: op.to_string(),
left: Box::new(l.to_owned()), left: Box::new(l.to_owned()),
right: Box::new(r), right: Box::new(r),
translation: trans.to_string(),
}) })
} }
} }
@ -546,8 +579,7 @@ fn parse_subscript_expr(
pad(just('.')) pad(just('.'))
.ignore_then(base) .ignore_then(base)
.map(|e| (SubscriptKind::Dot, e)), .map(|e| (SubscriptKind::Dot, e)),
rec rec.delimited_by(pad(just('[')), pad(just(']')))
.delimited_by(pad(just('[')), pad(just(']')))
.map(|e| (SubscriptKind::Bracket, e)), .map(|e| (SubscriptKind::Bracket, e)),
)) ))
.repeated(), .repeated(),
@ -581,11 +613,8 @@ fn parse_tuple_expr(
}) })
} }
fn parse_var_ref_expr(_m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone { fn parse_var_ref_expr(m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
pad(ident()) parse_identifier(m).map(Expr::VariableReference)
.separated_by(pad(just("::")))
.at_least(1)
.map(Expr::VariableReference)
} }
fn parse_literal(_m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone { fn parse_literal(_m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
@ -633,6 +662,15 @@ fn parse_literal(_m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char
pad(choice((int, float, string))).map(Expr::Literal) pad(choice((int, float, string))).map(Expr::Literal)
} }
fn parse_identifier(
_m: &ParserMeta,
) -> impl Parser<char, Identifier, Error = Simple<char>> + Clone {
pad(ident())
.separated_by(pad(just("::")))
.at_least(1)
.map(|elems| Identifier { elems })
}
fn parse_type(m: &ParserMeta) -> impl Parser<char, Type, Error = Simple<char>> { fn parse_type(m: &ParserMeta) -> impl Parser<char, Type, Error = Simple<char>> {
recursive(|rec| { recursive(|rec| {
choice(( choice((
@ -654,8 +692,8 @@ fn parse_type(m: &ParserMeta) -> impl Parser<char, Type, Error = Simple<char>> {
}) })
} }
fn parse_named_type(_m: &ParserMeta) -> impl Parser<char, Type, Error = Simple<char>> { fn parse_named_type(m: &ParserMeta) -> impl Parser<char, Type, Error = Simple<char>> {
pad(ident()).map(Type::Named) parse_identifier(m).map(Type::Named)
} }
fn parse_tuple_type( fn parse_tuple_type(
@ -861,6 +899,13 @@ mod tests {
.is_ok()) .is_ok())
} }
#[test]
fn multi_char_binary() {
assert!(parser(&ParserMeta::default())
.parse("def x = 2 >= 3;")
.is_ok())
}
#[test] #[test]
fn app() { fn app() {
assert!(parser(&ParserMeta::default()) assert!(parser(&ParserMeta::default())

View file

@ -23,7 +23,7 @@ pub enum Statement {
/// Declaration that a type implements a type class. /// Declaration that a type implements a type class.
InstanceDefinition { InstanceDefinition {
/// The name of the type class. /// The name of the type class.
class_name: String, class_name: Identifier,
/// The type that conforms to the type class. /// The type that conforms to the type class.
typ: Type, typ: Type,
@ -36,7 +36,7 @@ pub enum Statement {
/// Declaration of a type class. /// Declaration of a type class.
ClassDefinition { ClassDefinition {
/// The name of the class. /// The name of the class.
name: String, name: Identifier,
/// The type variable representing a type conforming to the class. /// The type variable representing a type conforming to the class.
var: String, var: String,
@ -58,7 +58,7 @@ pub enum ClassMember {
/// Declaration of a function or constant. /// Declaration of a function or constant.
Function { Function {
/// Name of the function. /// Name of the function.
name: String, name: Identifier,
/// The function arguments. /// The function arguments.
arguments: Vec<Pattern>, arguments: Vec<Pattern>,
@ -97,6 +97,9 @@ pub enum Expr {
/// The value being operated upon. /// The value being operated upon.
val: Box<Expr>, val: Box<Expr>,
/// The function that the unary operator translates to.
translation: String,
}, },
/// Binary operators, e.g., `5 + 5`. /// Binary operators, e.g., `5 + 5`.
@ -109,6 +112,9 @@ pub enum Expr {
/// The right side of the operator. /// The right side of the operator.
right: Box<Expr>, right: Box<Expr>,
/// The function that the binary operator translates to.
translation: String,
}, },
/// Function application, e.g., `sin x`. /// Function application, e.g., `sin x`.
@ -177,7 +183,7 @@ pub enum Expr {
Tuple(Vec<Expr>), Tuple(Vec<Expr>),
/// Variable references, possibly namespaced, e.g., `foo::bar::baz`. /// Variable references, possibly namespaced, e.g., `foo::bar::baz`.
VariableReference(Vec<String>), VariableReference(Identifier),
/// Literal tokens, e.g., strings and numbers. /// Literal tokens, e.g., strings and numbers.
Literal(Literal), Literal(Literal),
@ -187,7 +193,7 @@ pub enum Expr {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Type { pub enum Type {
/// `Foo` /// `Foo`
Named(String), Named(Identifier),
/// `List Int` /// `List Int`
Application { Application {
@ -245,6 +251,13 @@ pub enum Pattern {
Literal(Literal), 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<String>,
}
/// Literal values included in source code. /// Literal values included in source code.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Literal { pub enum Literal {