Skip to content

Commit aebbe20

Browse files
committed
maps
1 parent 5b141ab commit aebbe20

File tree

7 files changed

+145
-38
lines changed

7 files changed

+145
-38
lines changed

scout-interpreter/src/builtin.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
use std::{env, sync::Arc, thread::sleep, time::Duration};
1+
use std::{collections::HashMap, env, sync::Arc, thread::sleep, time::Duration};
22

33
use fantoccini::{
44
actions::{InputSource, KeyAction, KeyActions},
5+
client,
6+
cookies::Cookie,
57
elements::Element,
68
key::Key,
79
};
810
use futures::{future::BoxFuture, lock::Mutex, FutureExt, TryFutureExt};
11+
use scout_parser::ast::Identifier;
912

1013
use crate::{object::Object, EvalError, EvalResult, ScrapeResultsPtr};
1114

@@ -36,13 +39,15 @@ pub enum BuiltinKind {
3639
IsWhitespace,
3740
List,
3841
Push,
42+
Cookies,
43+
SetCookies,
3944
}
4045

4146
impl BuiltinKind {
4247
pub fn is_from(s: &str) -> Option<Self> {
4348
use BuiltinKind::*;
4449
match s {
45-
"is_whitespace" => Some(IsWhitespace),
50+
"isWhitespace" => Some(IsWhitespace),
4651
"url" => Some(Url),
4752
"number" => Some(Number),
4853
"args" => Some(Args),
@@ -55,10 +60,12 @@ impl BuiltinKind {
5560
"input" => Some(Input),
5661
"contains" => Some(Contains),
5762
"type" => Some(Type),
58-
"key_action" => Some(KeyPress),
63+
"keyAction" => Some(KeyPress),
5964
"sleep" => Some(Sleep),
6065
"list" => Some(List),
6166
"push" => Some(Push),
67+
"cookies" => Some(Cookies),
68+
"setCookies" => Some(SetCookies),
6269
_ => None,
6370
}
6471
}
@@ -71,6 +78,36 @@ impl BuiltinKind {
7178
) -> EvalResult {
7279
use BuiltinKind::*;
7380
match self {
81+
Cookies => {
82+
let cookies = crawler
83+
.get_all_cookies()
84+
.await?
85+
.iter()
86+
.map(|c| {
87+
(
88+
Identifier::new(c.name().to_string()),
89+
Arc::new(Object::Str(c.value().to_string())),
90+
)
91+
})
92+
.collect::<HashMap<Identifier, Arc<Object>>>();
93+
94+
Ok(Arc::new(Object::Map(Mutex::new(cookies))))
95+
}
96+
SetCookies => {
97+
assert_param_len!(args, 1);
98+
if let Object::Map(m) = &*args[0] {
99+
let inner = m.lock().await;
100+
crawler.delete_all_cookies().await?;
101+
for (key, val) in inner.iter() {
102+
let cookie = Cookie::new(key.name.clone(), val.to_string());
103+
crawler.add_cookie(cookie).await?;
104+
}
105+
106+
Ok(Arc::new(Object::Null))
107+
} else {
108+
Err(EvalError::InvalidFnParams)
109+
}
110+
}
74111
Push => {
75112
assert_param_len!(args, 2);
76113
match (&*args[0], args[1].clone()) {
@@ -236,7 +273,14 @@ impl BuiltinKind {
236273
_ => Err(EvalError::InvalidFnParams),
237274
},
238275
Object::List(v) => {
239-
let contains = v.lock().await.contains(&args[1]);
276+
let inner = v.lock().await;
277+
let mut contains = false;
278+
for obj in inner.iter() {
279+
if obj.eq(&args[1]).await {
280+
contains = true;
281+
break;
282+
}
283+
}
240284
Ok(Arc::new(Object::Boolean(contains)))
241285
}
242286
_ => Err(EvalError::InvalidFnParams),

scout-interpreter/src/lib.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ pub enum EvalError {
9191
UnknownIdent(Identifier),
9292
UnknownPrefixOp,
9393
UnknownInfixOp,
94+
UnknownKey(Identifier),
9495
UncaughtException,
9596
URLParseError(String),
9697
DuplicateDeclare,
@@ -230,6 +231,12 @@ fn eval_statement<'a>(
230231
}
231232
Ok(Arc::new(Object::Null))
232233
}
234+
(Object::Map(m), Object::Str(s)) => {
235+
let mut inner = m.lock().await;
236+
let ident = Identifier::new(s.clone());
237+
inner.insert(ident, val);
238+
Ok(Arc::new(Object::Null))
239+
}
233240
_ => Err(EvalError::InvalidIndex),
234241
}
235242
}
@@ -706,6 +713,17 @@ fn eval_expression<'a>(
706713
},
707714
ExprKind::Str(s) => Ok(Arc::new(Object::Str(s.to_owned()))),
708715
ExprKind::Number(n) => Ok(Arc::new(Object::Number(*n))),
716+
ExprKind::Map(map) => {
717+
let mut out = HashMap::new();
718+
719+
for (key, val) in map.pairs.iter() {
720+
let obj_val =
721+
eval_expression(val, crawler, env.clone(), results.clone()).await?;
722+
out.insert(key.clone(), obj_val);
723+
}
724+
725+
Ok(Arc::new(Object::Map(Mutex::new(out))))
726+
}
709727
ExprKind::Call(ident, params) => {
710728
apply_call(ident, params, crawler, None, env.clone(), results.clone()).await
711729
}
@@ -786,8 +804,8 @@ async fn eval_infix(
786804

787805
async fn eval_infix_op(lhs: Arc<Object>, op: &TokenKind, rhs: Arc<Object>) -> EvalResult {
788806
match op {
789-
TokenKind::EQ => Ok(Arc::new(Object::Boolean(lhs == rhs))),
790-
TokenKind::NEQ => Ok(Arc::new(Object::Boolean(lhs != rhs))),
807+
TokenKind::EQ => Ok(Arc::new(Object::Boolean(lhs.eq(&rhs).await))),
808+
TokenKind::NEQ => Ok(Arc::new(Object::Boolean(!lhs.eq(&rhs).await))),
791809
TokenKind::Plus => eval_plus_op(lhs, rhs),
792810
TokenKind::Minus => eval_minus_op(lhs, rhs),
793811
TokenKind::Asterisk => eval_asterisk_op(lhs, rhs),
@@ -828,6 +846,15 @@ async fn eval_index(lhs: Arc<Object>, idx: Arc<Object>) -> EvalResult {
828846
Err(EvalError::IndexOutOfBounds)
829847
}
830848
}
849+
(Object::Map(m), Object::Str(s)) => {
850+
let inner = m.lock().await;
851+
let ident = Identifier::new(s.clone());
852+
let mb_val = inner.get(&ident);
853+
match mb_val {
854+
Some(val) => Ok(val.clone()),
855+
None => Err(EvalError::UnknownIdent(ident)),
856+
}
857+
}
831858
(Object::Str(a), Object::Number(b)) => match a.chars().nth(*b as usize) {
832859
Some(c) => Ok(Arc::new(Object::Str(c.to_string()))),
833860
None => Err(EvalError::IndexOutOfBounds),

scout-interpreter/src/object.rs

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::env::EnvPointer;
99
#[derive(Debug)]
1010
pub enum Object {
1111
Null,
12-
Map(HashMap<Identifier, Arc<Object>>),
12+
Map(Mutex<HashMap<Identifier, Arc<Object>>>),
1313
Str(String),
1414
Node(fantoccini::elements::Element),
1515
List(Mutex<Vec<Arc<Object>>>),
@@ -62,11 +62,15 @@ impl Object {
6262
match self {
6363
Null => "Null".into(),
6464
Map(hash) => {
65-
let mut out = "{{".to_string();
66-
for (i, o) in hash.iter() {
67-
out.push_str(&format!("{}: {} ", i, o));
65+
let inner = hash.lock().await;
66+
let mut out = "{ ".to_string();
67+
for (idx, (i, o)) in inner.iter().enumerate() {
68+
out.push_str(&format!("{}: {}", i, o));
69+
if idx != inner.len() - 1 {
70+
out.push_str(", ");
71+
}
6872
}
69-
out.push_str("}}");
73+
out.push_str(" }");
7074
out
7175
}
7276
Str(s) => format!("\"{}\"", s),
@@ -92,23 +96,52 @@ impl Object {
9296
}
9397
.boxed()
9498
}
95-
}
9699

97-
impl PartialEq for Object {
98-
fn eq(&self, other: &Self) -> bool {
99-
use Object::*;
100-
match (self, other) {
101-
(Null, Null) => true,
102-
(Map(a), Map(b)) => a == b,
103-
(Str(a), Str(b)) => a == b,
104-
// @TODO: check if this is even correct
105-
(Node(a), Node(b)) => a.element_id() == b.element_id(),
106-
// @TODO: this requires async awaits....
107-
(List(_a), List(_b)) => false,
108-
(Boolean(a), Boolean(b)) => a == b,
109-
(Number(a), Number(b)) => a == b,
110-
_ => false,
100+
pub fn eq<'a>(&'a self, other: &'a Self) -> BoxFuture<'a, bool> {
101+
async move {
102+
use Object::*;
103+
match (self, other) {
104+
(Null, Null) => true,
105+
(Map(a), Map(b)) => {
106+
let a_i = a.lock().await;
107+
let b_i = b.lock().await;
108+
for key in a_i.keys() {
109+
match b_i.get(key) {
110+
Some(obj) => {
111+
if !a_i.get(key).unwrap().eq(obj).await {
112+
return false;
113+
}
114+
}
115+
None => return false,
116+
}
117+
}
118+
true
119+
}
120+
(Str(a), Str(b)) => a == b,
121+
// @TODO: check if this is even correct
122+
(Node(a), Node(b)) => a.element_id() == b.element_id(),
123+
(List(a), List(b)) => {
124+
let a_i = a.lock().await;
125+
let b_i = b.lock().await;
126+
127+
if a_i.len() != b_i.len() {
128+
return false;
129+
}
130+
131+
for idx in 0..(a_i.len() - 1) {
132+
if !a_i[idx].eq(&b_i[idx]).await {
133+
return false;
134+
}
135+
}
136+
137+
true
138+
}
139+
(Boolean(a), Boolean(b)) => a == b,
140+
(Number(a), Number(b)) => a == b,
141+
_ => false,
142+
}
111143
}
144+
.boxed()
112145
}
113146
}
114147

@@ -117,13 +150,6 @@ impl Display for Object {
117150
use Object::*;
118151
match self {
119152
Null => write!(f, "Null"),
120-
Map(hash) => {
121-
write!(f, "{{")?;
122-
for (i, o) in hash.iter() {
123-
write!(f, "{}: {} ", i, o)?;
124-
}
125-
write!(f, "}}")
126-
}
127153
Str(s) => write!(f, "\"{}\"", s),
128154
Node(_) => write!(f, "Node"),
129155
List(_objs) => write!(f, "list"),
@@ -155,7 +181,10 @@ impl Object {
155181
// @TODO handle this better
156182
Node(_) => Value::String("Node".to_owned()),
157183
List(list) => self.vec_to_json(list).await,
158-
Map(map) => Value::Object(obj_map_to_json(map).await),
184+
Map(map) => {
185+
let inner = map.lock().await;
186+
Value::Object(obj_map_to_json(&*inner).await)
187+
}
159188
Boolean(b) => Value::Bool(*b),
160189
Number(n) => json!(n),
161190
Fn(_, _) => panic!("cant serialize func"),
@@ -168,7 +197,7 @@ impl Object {
168197
match self {
169198
Null => false,
170199
Str(s) => !s.is_empty(),
171-
Map(m) => !m.is_empty(),
200+
Map(m) => !m.lock().await.is_empty(),
172201
List(v) => !v.lock().await.is_empty(),
173202
Boolean(b) => *b,
174203
// @TODO: Idk what truthiness of floats should be

scout-lib/keys.sct

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,5 @@ COMMAND = "\u{e03d}"
5959
// Executes a key press action with
6060
// the given key unicode value.
6161
def press(code) do
62-
key_action(code)
62+
keyAction(code)
6363
end

scout-lib/str.sct

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// from the left start of a given string.
33
def ltrim(s) do
44
i = 0
5-
while is_whitespace(s[i]) and i < len(s) do
5+
while isWhitespace(s[i]) and i < len(s) do
66
i = i + 1
77
end
88

@@ -18,7 +18,7 @@ end
1818
// from the right start of a given string.
1919
def rtrim(s) do
2020
i = len(s) - 1
21-
while is_whitespace(s[i]) and i > 0 do
21+
while isWhitespace(s[i]) and i > 0 do
2222
i = i - 1
2323
end
2424

scout-parser/src/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub enum ExprKind {
3939
Boolean(bool),
4040
Ident(Identifier),
4141
List(Vec<ExprKind>),
42+
Map(HashLiteral),
4243
Null,
4344

4445
// Selects

scout-parser/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ fn map_prefix_fn(kind: &TokenKind) -> Option<PrefixParseFn> {
6161
Str => Some(Parser::parse_str_literal),
6262
Null => Some(Parser::parse_null),
6363
LBracket => Some(Parser::parse_list_literal),
64+
LBrace => Some(Parser::parse_map),
6465
SelectAll => Some(Parser::parse_select_all),
6566
Select => Some(Parser::parse_select),
6667
Bang => Some(Parser::parse_prefix),
@@ -395,6 +396,11 @@ impl Parser {
395396
Ok(HashLiteral { pairs })
396397
}
397398

399+
fn parse_map(&mut self) -> ParseResult<ExprKind> {
400+
let lit = self.parse_hash_literal()?;
401+
Ok(ExprKind::Map(lit))
402+
}
403+
398404
fn parse_number_literal(&mut self) -> ParseResult<ExprKind> {
399405
Ok(ExprKind::Number(
400406
self.curr

0 commit comments

Comments
 (0)