Skip to content

Commit

Permalink
xparser: Parse literals as types
Browse files Browse the repository at this point in the history
  • Loading branch information
CohenArthur committed Apr 24, 2024
1 parent 6be993b commit a3ea472
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 17 deletions.
1 change: 1 addition & 0 deletions ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub enum TypeKind {
// probably simpler, right?
// but then how do we handle a simple type like "int" without generics or anything -> symbol(int) and empty vec for generics so we're good
Simple(Symbol), // FIXME: Can this be a symbol? Should it be something else? I think Symbol is fine, because the struct enclosing TypeKind has generics and location
Literal(Box<Ast>),
Multi(Vec<Type>),
FunctionLike(Vec<Type>, Option<Box<Type>>),
}
Expand Down
9 changes: 9 additions & 0 deletions flatten/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,16 @@ impl<'ast> Ctx<'ast> {
match &ty.kind {
// FIXME: Do we need to create a type reference here as well? `handle_multi_ty` returns the actual union type
TypeKind::Multi(variants) => ctx.handle_multi_type(ty, generics, variants),
TypeKind::Literal(ast) => {
let (ctx, idx) = ctx.visit(ast);

let data = FlattenData {
ast: AstInfo::Node(ast),
scope: ctx.scope,
};

ctx.append(data, Kind::TypeReference(idx))
}
TypeKind::Simple(_) => {
let data = FlattenData {
ast: AstInfo::Type(ty),
Expand Down
84 changes: 67 additions & 17 deletions xparser/src/constructs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use location::Location;
use location::SpanTuple;
use nom::sequence::tuple;
use nom::Err::Error as NomError;
use nom::Parser;
use nom::Slice;
use nom_locate::position;
use symbol::Symbol;
Expand Down Expand Up @@ -471,25 +472,53 @@ fn type_id(input: ParseInput) -> ParseResult<ParseInput, Type> {
},
))
} else {
let (input, (id, (start_loc, end_loc))) = spaced_identifier(input)?;
let kind = TypeKind::Simple(Symbol::from(id));
let (input, generics) = maybe_generic_application(input)?;
fn literal(input: ParseInput) -> ParseResult<ParseInput, Type> {
let (input, (location, kind)) = string_constant
.or(float_constant)
.or(int_constant)
.map(|literal| {
(
literal.location.clone(),
TypeKind::Literal(Box::new(literal)),
)
})
.parse(input)?;

Ok((
input,
Type {
kind,
generics: vec![],
location,
},
))
}

// FIXME: Refactor
let end_loc = if !generics.is_empty() {
position(input)?.1.into()
} else {
end_loc
};
fn type_symbol(input: ParseInput) -> ParseResult<ParseInput, Type> {
let (input, (kind, (start_loc, end_loc))) = spaced_identifier
.map(|(id, loc)| (TypeKind::Simple(Symbol::from(id)), loc))
.parse(input)?;

let (input, generics) = maybe_generic_application(input)?;

// FIXME: Refactor
let end_loc = if !generics.is_empty() {
position(input)?.1.into()
} else {
end_loc
};

Ok((
input,
Type {
kind,
generics,
location: pos_to_loc(input, start_loc, end_loc),
},
))
}

Ok((
input,
Type {
kind,
generics,
location: pos_to_loc(input, start_loc, end_loc),
},
))
type_symbol.or(literal).parse(input)
}
}

Expand Down Expand Up @@ -2295,4 +2324,25 @@ mod tests {
TypeKind::FunctionLike(..)
));
}

#[test]
fn parse_module_type() {
let input = span!("type foo = source[\"foo\"]");

assert!(expr(input).is_ok());
}

#[test]
fn parse_literal_type_in_function_arg() {
let input = span!("func only_accepts_foo_15(a: \"foo\", b: 15) {}");

assert!(expr(input).is_ok());
}

#[test]
fn parse_literal_type_in_generic_application() {
let input = span!("func foo(a: Foo[\"foo\"], b: Bar[15, 15.2]) {}");

assert!(expr(input).is_ok());
}
}

0 comments on commit a3ea472

Please sign in to comment.