Skip to content

Commit

Permalink
fix: Logical and/or and sql disambiguation
Browse files Browse the repository at this point in the history
  • Loading branch information
can-keklik committed Dec 23, 2023
1 parent 9e5a491 commit fee79ab
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 27 deletions.
25 changes: 19 additions & 6 deletions server/src/lang/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ use super::ast::sql::{
};
use super::ast::stmt::{Stmt, StmtId};
use super::ast::{Literal, ParserArena};
use super::token::SqlKeyword;
use crate::lang::token::{
Keyword, Keyword::*, Span, Spanned, SqlKeyword::*, Symbol::*, Token, TokenType, TokenType::*,
Keyword::*, Span, Spanned, SqlKeyword::*, Symbol::*, Token, TokenType, TokenType::*,
};
use crate::{kw, skw, sym};
use rustc_hash::FxHashMap;
Expand Down Expand Up @@ -406,7 +407,12 @@ impl<'a> Parser<'a> {

fn or(&mut self) -> ParseResult<ExprId> {
let expr = self.and()?;
if self.match_next(kw!(Keyword::Or)) {
let operator = if self.is_in_sql {
skw!(Or)
} else {
sym!(LogicalOr)
};
if self.match_next(operator) {
let op = self.peek_bw(1);
let right = self.and()?;
return Ok(self.arena.expression(Expr::Logical {
Expand All @@ -424,7 +430,12 @@ impl<'a> Parser<'a> {

fn and(&mut self) -> ParseResult<ExprId> {
let expr = self.equality()?;
if self.match_next(kw!(Keyword::And)) {
let operator = if self.is_in_sql {
skw!(And)
} else {
sym!(LogicalAnd)
};
if self.match_next(operator) {
let op = self.peek_bw(1);
let right = self.equality()?;
return Ok(self.arena.expression(Expr::Logical {
Expand Down Expand Up @@ -955,6 +966,8 @@ impl<'a> Parser<'a> {
Less => Operation::Less,
LessEqual => Operation::LessEqual,
Bang => Operation::Not,
LogicalAnd => Operation::And,
LogicalOr => Operation::Or,
Equal => {
println!("EQUAL");
if self.is_in_sql {
Expand All @@ -965,9 +978,9 @@ impl<'a> Parser<'a> {
}
_ => unreachable!(),
},
TokenType::Keyword(kw) => match kw {
Keyword::And => Operation::And,
Keyword::Or => Operation::Or,
TokenType::SqlKeyword(skw) => match skw {
SqlKeyword::And => Operation::And,
SqlKeyword::Or => Operation::Or,
_ => unreachable!(),
},
_ => unreachable!(),
Expand Down
42 changes: 34 additions & 8 deletions server/src/lang/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,31 @@ impl<'a> Scanner<'a> {

fn scan_double_token(&mut self, start: usize, c: char) -> Token {
self.advance();
if self.match_next('=') {
if self.match_next('&') && c == '&' {
Token {
tok_type: sym!(LogicalAnd),
literal: None,
lexeme: Some("&&".to_owned()),
span: Span {
start: start,
end: start + 2,
line: self.line,
line_end: self.line,
},
}
} else if self.match_next('|') && c == '|' {
Token {
tok_type: sym!(LogicalOr),
literal: None,
lexeme: Some("||".to_owned()),
span: Span {
start: start,
end: start + 2,
line: self.line,
line_end: self.line,
},
}
} else if self.match_next('=') {
Token {
tok_type: match c {
'!' => sym!(BangEqual),
Expand Down Expand Up @@ -306,7 +330,9 @@ impl<'a> Scanner<'a> {
'0'..='9' => Some(self.scan_number(start_idx)?),
'A'..='Z' | 'a'..='z' | '_' => Some(self.scan_identifier(start_idx, false)?),
'$' => Some(self.scan_identifier(start_idx, true)?),
'!' | '=' | '<' | '>' => Some(self.scan_double_token(start_idx, start_char)),
'!' | '=' | '<' | '>' | '|' | '&' => {
Some(self.scan_double_token(start_idx, start_char))
}
'/' => self.scan_slash(start_idx),
_ => Some(self.scan_other(start_idx, start_char)?),
};
Expand Down Expand Up @@ -830,22 +856,22 @@ mod test {
#[test]
fn test_keywords() {
assert_tokens(
"and or class else for function if break continue return super this var while loop",
"&& || class else for function if break continue return super this var while loop",
vec![
Token {
tok_type: kw!(Keyword::And),
lexeme: lexm!("and"),
tok_type: sym!(Symbol::LogicalAnd),
lexeme: lexm!("&&"),
literal: None,
span: Span {
line: 0,
start: 0,
end: 3,
end: 2,
line_end: 0,
},
},
Token {
tok_type: kw!(Keyword::Or),
lexeme: lexm!("or"),
tok_type: sym!(Symbol::LogicalOr),
lexeme: lexm!("||"),
literal: None,
span: Span {
line: 0,
Expand Down
6 changes: 2 additions & 4 deletions server/src/lang/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub enum Symbol {
Plus,
Slash,
Star,
LogicalAnd,
LogicalOr,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
Expand All @@ -48,8 +50,6 @@ pub enum TokenType {

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum Keyword {
And,
Or,
Class,
Else,
Fun,
Expand Down Expand Up @@ -182,13 +182,11 @@ pub static SYMBOLS: phf::Map<char, TokenType> = phf_map! {
};

pub static CASE_SNS_KEYWORDS: phf::Map<&'static str, TokenType> = phf_map! {
"and" => kw!(Keyword::And),
"class" => kw!(Keyword::Class),
"else" => kw!(Keyword::Else),
"for" => kw!(Keyword::For),
"function" => kw!(Keyword::Fun),
"if" => kw!(Keyword::If),
"or" => kw!(Keyword::Or),
"break" => kw!(Keyword::Break),
"continue" => kw!(Keyword::Continue),
"return" => kw!(Keyword::Return),
Expand Down
18 changes: 9 additions & 9 deletions server/src/runtime/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use crate::lang::ast::expr::{Expr, ExprId, Operation};
use crate::lang::ast::stmt::{Stmt, StmtId};
use crate::lang::ast::{Literal, ParserArena, Visitor};

use crate::lang::token::{Span};
use crate::lang::token::{Spanned};
use crate::lang::token::Span;
use crate::lang::token::Spanned;
use crate::runtime::environment::Environment;
use crate::runtime::types::RV::Callable;
use crate::runtime::types::{Function, RV};
Expand Down Expand Up @@ -552,13 +552,13 @@ mod test {
#[test]
fn test_logical_evaluation() {
let code = "
TestUtils.out(5 and 1);
TestUtils.out(5 or 1);
TestUtils.out(5 and 0);
TestUtils.out(5 or 0);
TestUtils.out(!(5 or 0));
TestUtils.out(!(5 or 0) or 1);
TestUtils.out(!(5 or 0) or (1 and 0));
TestUtils.out(5 && 1);
TestUtils.out(5 || 1);
TestUtils.out(5 && 0);
TestUtils.out(5 || 0);
TestUtils.out(!(5 || 0));
TestUtils.out(!(5 || 0) || 1);
TestUtils.out(!(5 || 0) || (1 && 0));
";
let (out, mut runtime) = get_runtime();
runtime.interpret(&code);
Expand Down

0 comments on commit fee79ab

Please sign in to comment.