forked from AbleScript/ablescript
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:
parent
ba019d3b7e
commit
eac86b5e0b
|
@ -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)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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*/);
|
||||||
|
|
|
@ -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*/]();
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
var hello = /*world*/;
|
dim hello /*world*/;
|
||||||
hello print;
|
hello print;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
var data;
|
dim data;
|
||||||
loop {
|
loop {
|
||||||
data read;
|
data read;
|
||||||
data print;
|
data print;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue