Skip to content

Commit a0b992a

Browse files
authored
feat(geth-eventql): support a record field as a first-class ast construct (#48)
1 parent d5aa7a1 commit a0b992a

File tree

5 files changed

+106
-48
lines changed

5 files changed

+106
-48
lines changed

geth-eventql/src/codegen.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use crate::{
2-
Expr, ExprVisitor, Literal, NodeAttributes, Operation, Query, QueryVisitor, Var, parser::Record,
3-
};
1+
use crate::{Expr, ExprVisitor, Literal, NodeAttributes, Operation, Query, QueryVisitor, Var};
42

53
pub enum Instr {
64
Push(Literal),
@@ -45,14 +43,8 @@ impl ExprVisitor for ExprCodegen<'_> {
4543
self.inner.instrs.push(Instr::LoadVar(var.clone()));
4644
}
4745

48-
fn enter_record_entry(&mut self, _attrs: &NodeAttributes, key: &str, _expr: &Expr) {
49-
self.inner
50-
.instrs
51-
.push(Instr::Push(Literal::String(key.to_string())));
52-
}
53-
54-
fn exit_record(&mut self, _attrs: &NodeAttributes, record: &Record) {
55-
self.inner.instrs.push(Instr::Rec(record.fields.len()));
46+
fn exit_record(&mut self, _attrs: &NodeAttributes, record: &[Expr]) {
47+
self.inner.instrs.push(Instr::Rec(record.len()));
5648
}
5749

5850
fn exit_array(&mut self, _attrs: &NodeAttributes, values: &[Expr]) {

geth-eventql/src/infer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Display};
33
use crate::{
44
Expr, Literal, Operation, Pos, Query, Scopes, Var,
55
error::InferError,
6-
parser::{ExprVisitorMut, NodeAttributes, QueryVisitorMut, Record},
6+
parser::{ExprVisitorMut, NodeAttributes, QueryVisitorMut},
77
};
88

99
pub struct InferedQuery {
@@ -238,7 +238,7 @@ impl ExprVisitorMut for TypecheckExpr<'_> {
238238
fn exit_record(
239239
&mut self,
240240
attrs: &mut NodeAttributes,
241-
_record: &mut Record,
241+
_record: &mut [Expr],
242242
) -> crate::Result<()> {
243243
if attrs.tpe != Type::Unspecified && attrs.tpe != Type::Record {
244244
bail!(attrs.pos, InferError::TypeMismatch(attrs.tpe, Type::Record));

geth-eventql/src/parser/ast.rs

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{collections::BTreeMap, fmt::Display, ptr::NonNull};
1+
use std::{fmt::Display, ptr::NonNull};
22

33
use crate::{
44
Pos, Type,
@@ -313,9 +313,9 @@ impl Expr {
313313
None
314314
}
315315

316-
pub fn as_record(&self) -> Option<&Record> {
317-
if let Value::Record(r) = &self.value {
318-
return Some(r);
316+
pub fn as_record(&self) -> Option<Rec<'_>> {
317+
if let Value::Record(inner) = &self.value {
318+
return Some(Rec { inner });
319319
}
320320

321321
None
@@ -344,6 +344,18 @@ impl Expr {
344344
visitor.on_var(&mut node.attrs, var)?;
345345
}
346346

347+
Value::Field { label, value } => {
348+
if item.visited {
349+
visitor.exit_field(&mut node.attrs, label.as_mut_str(), value.as_mut())?;
350+
continue;
351+
}
352+
353+
item.visited = true;
354+
visitor.enter_field(&mut node.attrs, label.as_mut_str(), value.as_mut())?;
355+
stack.push(item);
356+
stack.push(ItemMut::new(value.as_mut()));
357+
}
358+
347359
Value::Record(record) => {
348360
if item.visited {
349361
visitor.exit_record(&mut node.attrs, record)?;
@@ -354,8 +366,7 @@ impl Expr {
354366
visitor.enter_record(&mut node.attrs, record)?;
355367
stack.push(item);
356368

357-
for (key, expr) in record.fields.iter_mut() {
358-
visitor.enter_record_entry(&mut node.attrs, key, expr)?;
369+
for expr in record.iter_mut().rev() {
359370
stack.push(ItemMut::new(expr));
360371
}
361372
}
@@ -433,6 +444,18 @@ impl Expr {
433444
visitor.on_var(&item.value.attrs, var);
434445
}
435446

447+
Value::Field { label, value } => {
448+
if item.visited {
449+
visitor.exit_field(&item.value.attrs, label.as_str(), value);
450+
continue;
451+
}
452+
453+
item.visited = true;
454+
visitor.enter_field(&item.value.attrs, label.as_str(), value);
455+
stack.push(item);
456+
stack.push(Item::new(value));
457+
}
458+
436459
Value::Record(record) => {
437460
if item.visited {
438461
visitor.exit_record(&item.value.attrs, record);
@@ -441,11 +464,9 @@ impl Expr {
441464

442465
item.visited = true;
443466
visitor.enter_record(&item.value.attrs, record);
444-
let attrs = &item.value.attrs;
445467
stack.push(item);
446468

447-
for (key, expr) in record.fields.iter() {
448-
visitor.enter_record_entry(attrs, key, expr);
469+
for expr in record.iter().rev() {
449470
stack.push(Item::new(expr));
450471
}
451472
}
@@ -548,6 +569,24 @@ pub struct UnaryOp<'a> {
548569
pub expr: &'a Expr,
549570
}
550571

572+
pub struct Rec<'a> {
573+
inner: &'a Vec<Expr>,
574+
}
575+
576+
impl Rec<'_> {
577+
pub fn get(&self, id: &str) -> Option<&Expr> {
578+
for expr in self.inner.iter() {
579+
if let Value::Field { label, value } = &expr.value
580+
&& label == id
581+
{
582+
return Some(value);
583+
}
584+
}
585+
586+
None
587+
}
588+
}
589+
551590
pub struct ApplyFun<'a> {
552591
pub name: &'a String,
553592
pub params: &'a Vec<Expr>,
@@ -573,34 +612,35 @@ impl Display for Var {
573612

574613
pub enum Value {
575614
Literal(Literal),
615+
576616
Var(Var),
577-
Record(Record),
617+
618+
Field {
619+
label: String,
620+
value: Box<Expr>,
621+
},
622+
623+
Record(Vec<Expr>),
624+
578625
Array(Vec<Expr>),
626+
579627
App {
580628
fun: String,
581629
params: Vec<Expr>,
582630
},
631+
583632
Binary {
584633
lhs: Box<Expr>,
585634
op: Operation,
586635
rhs: Box<Expr>,
587636
},
637+
588638
Unary {
589639
op: Operation,
590640
expr: Box<Expr>,
591641
},
592642
}
593643

594-
pub struct Record {
595-
pub fields: BTreeMap<String, Expr>,
596-
}
597-
598-
impl Record {
599-
pub fn get(&self, id: &str) -> Option<&Expr> {
600-
self.fields.get(id)
601-
}
602-
}
603-
604644
pub struct Sort {
605645
pub expr: Expr,
606646
pub order: Order,
@@ -746,24 +786,33 @@ pub trait ExprVisitorMut {
746786
fn enter_record(
747787
&mut self,
748788
attrs: &mut NodeAttributes,
749-
record: &mut Record,
789+
record: &mut [Expr],
750790
) -> crate::Result<()> {
751791
Ok(())
752792
}
753793

754-
fn enter_record_entry(
794+
fn enter_field(
755795
&mut self,
756796
attrs: &mut NodeAttributes,
757-
key: &str,
758-
expr: &mut Expr,
797+
label: &mut str,
798+
value: &mut Expr,
799+
) -> crate::Result<()> {
800+
Ok(())
801+
}
802+
803+
fn exit_field(
804+
&mut self,
805+
attrs: &mut NodeAttributes,
806+
label: &mut str,
807+
value: &mut Expr,
759808
) -> crate::Result<()> {
760809
Ok(())
761810
}
762811

763812
fn exit_record(
764813
&mut self,
765814
attrs: &mut NodeAttributes,
766-
record: &mut Record,
815+
record: &mut [Expr],
767816
) -> crate::Result<()> {
768817
Ok(())
769818
}
@@ -872,9 +921,10 @@ pub trait QueryVisitor {
872921
pub trait ExprVisitor {
873922
fn on_literal(&mut self, attrs: &NodeAttributes, lit: &Literal) {}
874923
fn on_var(&mut self, attrs: &NodeAttributes, var: &Var) {}
875-
fn enter_record(&mut self, attrs: &NodeAttributes, record: &Record) {}
876-
fn enter_record_entry(&mut self, attrs: &NodeAttributes, key: &str, expr: &Expr) {}
877-
fn exit_record(&mut self, attrs: &NodeAttributes, record: &Record) {}
924+
fn enter_record(&mut self, attrs: &NodeAttributes, record: &[Expr]) {}
925+
fn enter_field(&mut self, attrs: &NodeAttributes, label: &str, value: &Expr) {}
926+
fn exit_field(&mut self, attrs: &NodeAttributes, label: &str, value: &Expr) {}
927+
fn exit_record(&mut self, attrs: &NodeAttributes, record: &[Expr]) {}
878928
fn enter_array(&mut self, attrs: &NodeAttributes, values: &[Expr]) {}
879929
fn exit_array(&mut self, attrs: &NodeAttributes, values: &[Expr]) {}
880930
fn enter_app(&mut self, attrs: &NodeAttributes, name: &str, params: &[Expr]) {}

geth-eventql/src/parser/mod.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use crate::{
33
sym::{Keyword, Literal, Sym},
44
tokenizer::{Lexer, Pos},
55
};
6-
use std::collections::BTreeMap;
76

87
mod ast;
98
mod state;
@@ -406,15 +405,22 @@ fn parse_expr_single(state: &mut ParserState<'_>) -> crate::Result<Expr> {
406405
Sym::LBrace => {
407406
state.skip_whitespace()?;
408407

409-
let mut fields = BTreeMap::new();
408+
let mut fields = Vec::new();
410409

411410
while let Some(Sym::Id(id)) = state.look_ahead()? {
412-
let id = id.clone();
411+
let label = id.clone();
412+
let label_pos = state.pos();
413413
state.shift()?;
414414
state.skip_whitespace()?;
415415
state.expect(Sym::Colon)?;
416416
state.skip_whitespace()?;
417-
fields.insert(id, parse_expr_single(state)?);
417+
fields.push(Expr {
418+
attrs: NodeAttributes::new(label_pos),
419+
value: Value::Field {
420+
label,
421+
value: Box::new(parse_expr_single(state)?),
422+
},
423+
});
418424
state.skip_whitespace()?;
419425

420426
if let Some(Sym::Comma) = state.look_ahead()? {
@@ -430,7 +436,7 @@ fn parse_expr_single(state: &mut ParserState<'_>) -> crate::Result<Expr> {
430436

431437
Ok(Expr {
432438
attrs: NodeAttributes::new(pos),
433-
value: Value::Record(Record { fields }),
439+
value: Value::Record(fields),
434440
})
435441
}
436442

geth-eventql/src/rename.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::{
77
use crate::{
88
Expr, Literal, Query, Value, Var,
99
error::RenameError,
10-
parser::{ExprVisitorMut, NodeAttributes, QueryVisitorMut, Record, parse_subject},
10+
parser::{ExprVisitorMut, NodeAttributes, QueryVisitorMut, parse_subject},
1111
};
1212

1313
pub fn rename(query: &mut Query) -> crate::Result<Scopes> {
@@ -160,10 +160,20 @@ impl ExprVisitorMut for RenameExpr<'_> {
160160
Ok(())
161161
}
162162

163+
fn exit_field(
164+
&mut self,
165+
attrs: &mut NodeAttributes,
166+
_label: &mut str,
167+
value: &mut Expr,
168+
) -> crate::Result<()> {
169+
attrs.scope = value.attrs.scope;
170+
Ok(())
171+
}
172+
163173
fn exit_record(
164174
&mut self,
165175
attrs: &mut NodeAttributes,
166-
_record: &mut Record,
176+
_record: &mut [Expr],
167177
) -> crate::Result<()> {
168178
attrs.scope = self.inner.scope_id();
169179

0 commit comments

Comments
 (0)