Changed variable declaration / assignment and equals syntax:

- `dim <ident> [value];` is now used for declaration
- `<value> =: <assignable>` is used for assignments
- As token `=` doesn't cause any ambiguity now, it can be used for equals operation
This commit is contained in:
Erin 2022-04-18 20:34:08 +02:00 committed by ondra05
parent ba019d3b7e
commit eac86b5e0b
10 changed files with 88 additions and 59 deletions

View file

@ -113,7 +113,7 @@ pub enum Stmt {
Break, Break,
HopBack, HopBack,
Var { Dim {
ident: Spanned<String>, ident: Spanned<String>,
init: Option<Spanned<Expr>>, init: Option<Spanned<Expr>>,
}, },
@ -186,7 +186,7 @@ impl BinOpKind {
Token::FwdSlash => Ok(Self::Divide), Token::FwdSlash => Ok(Self::Divide),
Token::GreaterThan => Ok(Self::Greater), Token::GreaterThan => Ok(Self::Greater),
Token::LessThan => Ok(Self::Less), Token::LessThan => Ok(Self::Less),
Token::EqualEqual => Ok(Self::Equal), Token::Equals => Ok(Self::Equal),
Token::Aint => Ok(Self::NotEqual), Token::Aint => Ok(Self::NotEqual),
t => Err(crate::error::ErrorKind::UnexpectedToken(t)), t => Err(crate::error::ErrorKind::UnexpectedToken(t)),
} }

View file

@ -209,7 +209,7 @@ impl ExecEnv {
Stmt::Print(expr) => { Stmt::Print(expr) => {
println!("{}", self.eval_expr(expr)?); println!("{}", self.eval_expr(expr)?);
} }
Stmt::Var { ident, init } => { Stmt::Dim { ident, init } => {
let init = match init { let init = match init {
Some(e) => self.eval_expr(e)?, Some(e) => self.eval_expr(e)?,
None => Value::Nul, None => Value::Nul,
@ -719,7 +719,7 @@ mod tests {
let mut env = ExecEnv::new(); let mut env = ExecEnv::new();
// Declaring and reading from a variable. // Declaring and reading from a variable.
eval(&mut env, "var foo = 32; var bar = foo + 1;").unwrap(); eval(&mut env, "dim foo 32; dim bar foo + 1;").unwrap();
assert_eq!( assert_eq!(
env.get_var(&Spanned { env.get_var(&Spanned {
item: "bar".to_owned(), item: "bar".to_owned(),
@ -730,7 +730,7 @@ mod tests {
); );
// Assigning an existing variable. // Assigning an existing variable.
eval(&mut env, "foo = /*hi*/;").unwrap(); eval(&mut env, "/*hi*/ =: foo;").unwrap();
assert_eq!( assert_eq!(
env.get_var(&Spanned { env.get_var(&Spanned {
item: "foo".to_owned(), item: "foo".to_owned(),
@ -742,7 +742,7 @@ mod tests {
// But variable assignment should be illegal when the variable // But variable assignment should be illegal when the variable
// hasn't been declared in advance. // hasn't been declared in advance.
eval(&mut env, "invalid = bar + 1;").unwrap_err(); eval(&mut env, "bar + 1 =: invalid;").unwrap_err();
} }
#[test] #[test]
@ -753,7 +753,7 @@ mod tests {
let mut env = ExecEnv::new(); let mut env = ExecEnv::new();
eval( eval(
&mut env, &mut env,
"var foo = 1; foo = 2; if (always) { var foo = 3; foo = 4; }", "dim foo 1; 2 =: foo; if (always) { dim foo 3; 4 =: foo; }",
) )
.unwrap(); .unwrap();

View file

@ -40,8 +40,8 @@ pub enum Token {
#[token("/")] #[token("/")]
FwdSlash, FwdSlash,
#[token("=")] #[token("=:")]
Equal, Assign,
#[token("<=")] #[token("<=")]
Arrow, Arrow,
@ -53,8 +53,8 @@ pub enum Token {
#[token(">")] #[token(">")]
GreaterThan, GreaterThan,
#[token("==")] #[token("=")]
EqualEqual, Equals,
#[token("ain't")] #[token("ain't")]
Aint, Aint,
@ -68,8 +68,8 @@ pub enum Token {
Bff, Bff,
/// Variable bro /// Variable bro
#[token("var")] #[token("dim")]
Var, Dim,
/// Prints the preceding things /// Prints the preceding things
#[token("print")] #[token("print")]
@ -152,24 +152,25 @@ mod tests {
#[test] #[test]
fn simple_fn() { fn simple_fn() {
let code = "functio test() { var a = 3; if a == 3 { a print } }"; let code = "functio test() { dim var 3; if (var = 3) { var print } }";
let expected = &[ let expected = &[
Functio, Functio,
Identifier("test".to_owned()), Identifier("test".to_owned()),
LeftParen, LeftParen,
RightParen, RightParen,
LeftCurly, LeftCurly,
Var, Dim,
Identifier("a".to_owned()), Identifier("var".to_owned()),
Equal,
Integer(3), Integer(3),
Semicolon, Semicolon,
If, If,
Identifier("a".to_owned()), LeftParen,
EqualEqual, Identifier("var".to_owned()),
Equals,
Integer(3), Integer(3),
RightParen,
LeftCurly, LeftCurly,
Identifier("a".to_owned()), Identifier("var".to_owned()),
Print, Print,
RightCurly, RightCurly,
RightCurly, RightCurly,

View file

@ -73,7 +73,7 @@ impl<'source> Parser<'source> {
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Bff => Ok(Spanned::new(self.bff_flow()?, start..self.lexer.span().end)), Token::Bff => Ok(Spanned::new(self.bff_flow()?, start..self.lexer.span().end)),
Token::Var => Ok(Spanned::new(self.var_flow()?, start..self.lexer.span().end)), Token::Dim => Ok(Spanned::new(self.dim_flow()?, start..self.lexer.span().end)),
Token::Melo => Ok(Spanned::new( Token::Melo => Ok(Spanned::new(
self.melo_flow()?, self.melo_flow()?,
start..self.lexer.span().end, start..self.lexer.span().end,
@ -209,7 +209,7 @@ impl<'source> Parser<'source> {
| Token::Minus | Token::Minus
| Token::Star | Token::Star
| Token::FwdSlash | Token::FwdSlash
| Token::EqualEqual | Token::Equals
| Token::LessThan | Token::LessThan
| Token::GreaterThan | Token::GreaterThan
| Token::Aint => Ok(Spanned::new( | Token::Aint => Ok(Spanned::new(
@ -382,17 +382,13 @@ impl<'source> Parser<'source> {
} }
// Variable Assignment // Variable Assignment
Token::Equal => { Token::Assign => {
if let Some(Ok(assignable)) = buf.take().map(Assignable::from_expr) { return match buf.take() {
break Stmt::Assign { Some(expr) => self.assignment_flow(expr),
assignable, None => Err(Error::new(
value: self.expr_flow(Token::Semicolon)?, ErrorKind::UnexpectedToken(Token::Assign),
};
} else {
return Err(Error::new(
ErrorKind::UnexpectedToken(Token::Equal),
self.lexer.span(), self.lexer.span(),
)); )),
} }
} }
@ -546,15 +542,47 @@ impl<'source> Parser<'source> {
} }
/// Parse variable declaration /// Parse variable declaration
fn var_flow(&mut self) -> Result<Stmt, Error> { fn dim_flow(&mut self) -> Result<Stmt, Error> {
let ident = self.get_ident()?; let ident = self.get_ident()?;
let init = match self.checked_next()? { let mut init = None;
Token::Equal => Some(self.expr_flow(Token::Semicolon)?), loop {
Token::Semicolon => None, match self.checked_next()? {
Token::Semicolon => break,
t => init = Some(self.parse_expr(t, &mut init)?),
}
}
Ok(Stmt::Dim { ident, init })
}
/// Parse assignment to assignable
fn assignment_flow(&mut self, value: Spanned<Expr>) -> Result<Stmt, Error> {
let ident = self.get_ident()?;
let kind = match self.checked_next()? {
Token::Semicolon => AssignableKind::Variable,
Token::LeftBracket => {
let mut indices = vec![];
loop {
indices.push(self.expr_flow(Token::RightBracket)?);
match self.checked_next()? {
Token::Semicolon => break AssignableKind::Index { indices },
Token::LeftBracket => (),
t => {
return Err(Error::new(
ErrorKind::UnexpectedToken(t),
self.lexer.span(),
))
}
}
}
}
t => return Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())), t => return Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())),
}; };
Ok(Stmt::Var { ident, init }) Ok(Stmt::Assign {
assignable: Assignable { ident, kind },
value,
})
} }
/// Parse Melo flow /// Parse Melo flow
@ -624,9 +652,9 @@ mod tests {
#[test] #[test]
fn variable_declaration() { fn variable_declaration() {
let code = "var a = 42;"; let code = "dim a 42;";
let expected = &[Spanned { let expected = &[Spanned {
item: Stmt::Var { item: Stmt::Dim {
ident: Spanned { ident: Spanned {
item: "a".to_owned(), item: "a".to_owned(),
span: 4..5, span: 4..5,
@ -645,7 +673,7 @@ mod tests {
#[test] #[test]
fn if_flow() { fn if_flow() {
let code = "if (a == always) { /*Buy Able products!*/ print; }"; let code = "if (a = always) { /*Buy Able products!*/ print; }";
let expected = &[Spanned { let expected = &[Spanned {
item: Stmt::If { item: Stmt::If {
cond: Spanned { cond: Spanned {
@ -679,9 +707,9 @@ mod tests {
#[test] #[test]
fn tdark() { fn tdark() {
let code = "T-Dark { var lang = /*lang*/ + lang; }"; let code = "T-Dark { dim lang /*lang*/ + lang; }";
let expected = &[Spanned { let expected = &[Spanned {
item: Stmt::Var { item: Stmt::Dim {
ident: Spanned { ident: Spanned {
item: "script".to_owned(), item: "script".to_owned(),
span: 13..17, span: 13..17,

View file

@ -25,20 +25,20 @@ owo arity_1(/*foo*/);
owo arity_2(/*foo*/, /*bar*/); owo arity_2(/*foo*/, /*bar*/);
owo arity_3(/*foo*/, /*bar*/, /*baz*/); owo arity_3(/*foo*/, /*bar*/, /*baz*/);
var i1 = arity_0 * arity_1; dim i1 arity_0 * arity_1;
i1(/*second*/); i1(/*second*/);
/*----*/ print; /*----*/ print;
var i2 = arity_1 * arity_0; dim i2 arity_1 * arity_0;
i2(/*first*/); i2(/*first*/);
/*----*/ print; /*----*/ print;
var ifancy = arity_3 * arity_3; dim ifancy arity_3 * arity_3;
ifancy(/*left1*/, /*right1*/, /*left2*/, /*right2*/, /*left3*/, /*right3*/); ifancy(/*left1*/, /*right1*/, /*left2*/, /*right2*/, /*left3*/, /*right3*/);
/*---*/" print; /*---*/ print;
var another = arity_0 * arity_3; dim another arity_0 * arity_3;
another(/*right1*/, /*right2*/, /*right3*/); another(/*right1*/, /*right2*/, /*right3*/);

View file

@ -1,8 +1,8 @@
functio helloable() { functio helloable() {
"´/*Hello, Able!*/ print; /*Hello, Able!*/ print;
} }
var cart = [/*able*/ <= 42, helloable <= /*hello*/]; dim cart [/*able*/ <= 42, helloable <= /*hello*/];
cart[42] print; cart[42] print;
cart[/*hello*/](); cart[/*hello*/]();

View file

@ -1,2 +1,2 @@
var hello = /*world*/; dim hello /*world*/;
hello print; hello print;

View file

@ -1,4 +1,4 @@
var data; dim data;
loop { loop {
data read; data read;
data print; data print;

View file

@ -1,3 +1,3 @@
var hi = /*wonk*/; dim hi /*wonk*/;
melo hi; melo hi;
hi print; owo Should error out hi print; owo Should error out

View file

@ -2,22 +2,22 @@ owo Pass-by-reference test
owo Swap two variables. owo Swap two variables.
functio swap(left, right) { functio swap(left, right) {
var tmp = left; dim tmp left;
left = right; right =: left;
right = tmp; tmp =: right;
} }
var foo = /*hello*/; dim foo /*hello*/;
var bar = /*world*/; dim bar /*world*/;
swap(foo, bar); swap(foo, bar);
if (foo != /*world*/) { if (foo ain't /*world*/) {
/*FAILED*/ print; /*FAILED*/ print;
/*foo should be 'world', is actually:*/ print; /*foo should be 'world', is actually:*/ print;
foo print; foo print;
} }
if (foo == /*world*/) { if (foo = /*world*/) {
/*OK*/ print; /*OK*/ print;
} }