Parse all namespaced identifiers

main
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
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);

View File

@ -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<Associativity>,
/// 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<char, Statement, Error = Simple<char>> + '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<char, ClassMember, Error = Simple<char>> + '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<char, Statement, Error = Simple<char>> + '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::<Vec<_>>();
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<char, Expr, Error = Simple<char>> + Clone {
pad(ident())
.separated_by(pad(just("::")))
.at_least(1)
.map(Expr::VariableReference)
fn parse_var_ref_expr(m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
parse_identifier(m).map(Expr::VariableReference)
}
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)
}
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>> {
recursive(|rec| {
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>> {
pad(ident()).map(Type::Named)
fn parse_named_type(m: &ParserMeta) -> impl Parser<char, Type, Error = Simple<char>> {
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())

View File

@ -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<Pattern>,
@ -97,6 +97,9 @@ pub enum Expr {
/// The value being operated upon.
val: Box<Expr>,
/// 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<Expr>,
/// 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<Expr>),
/// Variable references, possibly namespaced, e.g., `foo::bar::baz`.
VariableReference(Vec<String>),
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<String>,
}
/// Literal values included in source code.
#[derive(Clone, Debug)]
pub enum Literal {