Compare commits

...

3 commits

Author SHA1 Message Date
Alain Zscheile
ed6c52f120 introduce symbol to indicate matching, now used on all single-arg invocations 2023-05-22 21:42:14 +02:00
Alain Zscheile
23490cc237 make parsing a bit nicer
This also merges the `match` and single-call interface.
Modules can simply be called with tags.
2023-05-22 21:32:54 +02:00
Alain Zscheile
f0235832c3 parse 'tag' expressions 2023-05-22 21:17:30 +02:00
3 changed files with 56 additions and 39 deletions

View file

@ -35,8 +35,8 @@ as an argument, prefix the block with `'`.
## Control flow builtins ## Control flow builtins
- `cflow.if, cond = ..., then = ..., else = ...` - `cflow.if, cond = ..., then = ..., else = ...`
- `cflow.loop ...` - `cflow.loop § ...`
- `cflow.return ...` (implicit when last expr in a block is not terminated via semicolon) - `cflow.return § ...` (implicit when last expr in a block is not terminated via semicolon)
## Modules ## Modules
@ -61,7 +61,7 @@ with package-lock files or such. Packages (packaged module trees) would then be
# 1. # 1.
final main { args env } = { final main { args env } = {
std.io.writeln "Hello World!"; std.io.writeln § "Hello World!";
0 0
}; };
@ -72,7 +72,7 @@ with package-lock files or such. Packages (packaged module trees) would then be
what_now = { what_now = {
self.business_in_the_front; self.business_in_the_front;
}, self.party_in_the_back { }, self.party_in_the_back {
std.io.writeln "It works"; std.io.writeln § "It works";
}; };
# running `what_now` results in "It works" being printed. # running `what_now` results in "It works" being printed.

View file

@ -6,7 +6,6 @@ pub enum Token<'a> {
CtrlFlowEdit, CtrlFlowEdit,
Defer, Defer,
Final, Final,
Match,
Module, Module,
Public, Public,
Tag, Tag,
@ -15,9 +14,12 @@ pub enum Token<'a> {
Assign, Assign,
OpenBrace, OpenBrace,
CloseBrace, CloseBrace,
OpenParen,
CloseParen,
Comma, Comma,
SemiColon, SemiColon,
Dot, Dot,
MatchPara,
// dynamic stuff // dynamic stuff
/// amount of prefixed `$` to force immediate application /// amount of prefixed `$` to force immediate application
@ -32,11 +34,6 @@ impl Token<'_> {
pub fn is_def_attr(&self) -> bool { pub fn is_def_attr(&self) -> bool {
matches!(self, Token::Final) matches!(self, Token::Final)
} }
#[inline]
pub fn is_cobj_attr(&self) -> bool {
matches!(self, Token::CtrlFlowEdit)
}
} }
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
@ -106,15 +103,18 @@ impl<'a> Iterator for Lexer<'a> {
let x = self.s.chars().next()?; let x = self.s.chars().next()?;
let loc = self.loc; let loc = self.loc;
let rtok = match x { let rtok = match x {
'{' | '}' | '=' | ',' | ';' | '.' => { '{' | '}' | '(' | ')' | '=' | ',' | ';' | '.' | ' => {
self.eat(x.len_utf8()); self.eat(x.len_utf8());
match x { match x {
'{' => Token::OpenBrace, '{' => Token::OpenBrace,
'}' => Token::CloseBrace, '}' => Token::CloseBrace,
'(' => Token::OpenParen,
')' => Token::CloseParen,
'=' => Token::Assign, '=' => Token::Assign,
',' => Token::Comma, ',' => Token::Comma,
';' => Token::SemiColon, ';' => Token::SemiColon,
'.' => Token::Dot, '.' => Token::Dot,
'§' => Token::MatchPara,
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -179,7 +179,6 @@ impl<'a> Iterator for Lexer<'a> {
"cfe" => Token::CtrlFlowEdit, "cfe" => Token::CtrlFlowEdit,
"defer" => Token::Defer, "defer" => Token::Defer,
"final" => Token::Final, "final" => Token::Final,
"match" => Token::Match,
"module" => Token::Module, "module" => Token::Module,
"pub" => Token::Public, "pub" => Token::Public,
"tag" => Token::Tag, "tag" => Token::Tag,

View file

@ -50,10 +50,7 @@ pub enum Expression {
obj: Box<Expression>, obj: Box<Expression>,
args: BTreeMap<Box<[Atom]>, (Location, Expression)>, args: BTreeMap<Box<[Atom]>, (Location, Expression)>,
}, },
Tag { Tag(Path),
obj: Box<Expression>,
args: BTreeMap<Box<[Atom]>, (Location, Expression)>,
},
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -79,6 +76,7 @@ pub enum ErrorKind {
UnexpectedTrail, UnexpectedTrail,
InvalidIdentifier, InvalidIdentifier,
DuplicateIdentifier, DuplicateIdentifier,
InvalidCombination(&'static str),
Unexpected(&'static str), Unexpected(&'static str),
Unknown, Unknown,
} }
@ -184,7 +182,10 @@ impl FullIdentifier {
impl Expression { impl Expression {
fn parse_high(ctx: &mut ParserContext<'_>) -> Result<Self, Error> { fn parse_high(ctx: &mut ParserContext<'_>) -> Result<Self, Error> {
let mut cfe = false; let mut cfe = false;
for (_, i) in ctx.pklx.peeking_take_while(|(_, t)| t.is_cobj_attr()) { for (_, i) in ctx
.pklx
.peeking_take_while(|(_, t)| matches!(t, Token::CtrlFlowEdit))
{
match i { match i {
Token::CtrlFlowEdit => cfe = true, Token::CtrlFlowEdit => cfe = true,
_ => unimplemented!(), _ => unimplemented!(),
@ -224,9 +225,12 @@ impl Expression {
loc, loc,
kind: ErrorKind::Unexpected("braced statement set"), kind: ErrorKind::Unexpected("braced statement set"),
}), }),
// we have no proper recursive delimiting, Some((_, Token::OpenParen)) => {
// so just resort to the parsing which we also do for other such items, ctx.pklx.next();
// expect a single code object descriptor => alias, or number. let inner = Expression::parse_high(ctx)?;
ctx.expect_token(Token::CloseParen, /* ( */ ")")?;
Ok(inner)
}
Some(&(_, Token::Integer(i))) => { Some(&(_, Token::Integer(i))) => {
ctx.pklx.next(); ctx.pklx.next();
Ok(Expression::Integer(i)) Ok(Expression::Integer(i))
@ -238,31 +242,45 @@ impl Expression {
ctx.expect_token(Token::CloseBrace, "}")?; ctx.expect_token(Token::CloseBrace, "}")?;
Ok(Expression::Module(m)) Ok(Expression::Module(m))
} }
Some((_, Token::Tag)) => {
ctx.pklx.next();
Path::parse_high(ctx).map(Expression::Tag)
}
_ => FullIdentifier::parse_high(ctx).map(Expression::Alias), _ => FullIdentifier::parse_high(ctx).map(Expression::Alias),
}?; }?;
Ok(if let Some(&(_, Token::Comma)) = ctx.pklx.peek() { match ctx.pklx.peek() {
let mut args = BTreeMap::new(); None | Some((_, Token::SemiColon | Token::CloseBrace | Token::CloseParen)) => Ok(obj),
while ctx.maybe_eat_token(Token::Comma).is_some() { Some((_, Token::Comma)) => {
let Path { loc, idents } = Path::parse_high(ctx)?; let mut args = BTreeMap::new();
ctx.expect_token(Token::Assign, "=")?; while ctx.maybe_eat_token(Token::Comma).is_some() {
let obj = Expression::parse_high(ctx)?; let Path { loc, idents } = Path::parse_high(ctx)?;
if args.insert(idents, (loc, obj)).is_some() { ctx.expect_token(Token::Assign, "=")?;
return Err(Error { let obj = Expression::parse_high(ctx)?;
loc, if args.insert(idents, (loc, obj)).is_some() {
kind: ErrorKind::DuplicateIdentifier, return Err(Error {
}); loc,
kind: ErrorKind::DuplicateIdentifier,
});
}
} }
Ok(Expression::InvocationMulti {
obj: Box::new(obj),
args,
})
} }
Expression::InvocationMulti { Some((_, Token::MatchPara)) => {
obj: Box::new(obj), ctx.pklx.next();
args, Ok(Expression::InvocationSingle(Box::new((
obj,
Expression::parse_high(ctx)?,
))))
} }
} else if matches!(ctx.pklx.peek(), Some(&(_, Token::SemiColon)) | None) { _ => Err(Error {
obj loc: ctx.peek_loc(),
} else { kind: ErrorKind::Unexpected("end of expression"),
Expression::InvocationSingle(Box::new((obj, Expression::parse_high(ctx)?))) }),
}) }
} }
} }