ucglib/build/opcode/
translate.rs

1// Copyright 2019 Jeremy Wall
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14use std::collections::BTreeMap;
15use std::path::Path;
16
17use crate::ast::walk::Walker;
18use crate::ast::{
19    BinaryExprType, BinaryOpDef, Expression, FormatArgs, FuncOpDef, Position, PositionedItem,
20    Rewriter, SelectDef, Statement, TemplatePart, Token, TokenType, Value,
21};
22use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser};
23use crate::build::opcode::Primitive;
24use crate::build::opcode::{Hook, Op};
25
26pub struct AST();
27
28#[derive(Debug, PartialEq)]
29pub struct OpsMap {
30    pub ops: Vec<Op>,
31    pub pos: Vec<Position>,
32    pub links: BTreeMap<String, Position>,
33}
34
35impl OpsMap {
36    pub fn new() -> Self {
37        OpsMap {
38            ops: Vec::new(),
39            pos: Vec::new(),
40            links: BTreeMap::new(),
41        }
42    }
43
44    pub fn with_ops(mut self, ops: Vec<Op>, pos: Vec<Position>) -> Self {
45        self.ops = ops;
46        self.pos = pos;
47        self
48    }
49
50    pub fn add_link(&mut self, path: String, pos: Position) {
51        self.links.insert(path, pos);
52    }
53
54    pub fn len(&self) -> usize {
55        self.ops.len()
56    }
57
58    pub fn push(&mut self, op: Op, pos: Position) {
59        self.ops.push(op);
60        self.pos.push(pos);
61    }
62
63    pub fn replace(&mut self, idx: usize, op: Op) {
64        self.ops[idx] = op;
65    }
66}
67
68impl AST {
69    pub fn translate<P: AsRef<Path>>(mut stmts: Vec<Statement>, root: &P) -> OpsMap {
70        let mut rewriter = Rewriter::new(root.as_ref());
71        let mut_stmts = stmts.iter_mut().collect();
72        rewriter.walk_statement_list(mut_stmts);
73        let mut ops = OpsMap::new();
74        Self::translate_stmts(stmts, &mut ops, root.as_ref());
75        return ops;
76    }
77
78    fn translate_stmt(stmt: Statement, mut ops: &mut OpsMap, root: &Path) {
79        match stmt {
80            Statement::Expression(expr) => {
81                let expr_pos = expr.pos().clone();
82                Self::translate_expr(expr, &mut ops, root);
83                ops.push(Op::Pop, expr_pos);
84            }
85            Statement::Assert(pos, expr) => {
86                Self::translate_expr(expr, &mut ops, root);
87                ops.push(Op::Runtime(Hook::Assert), pos);
88            }
89            Statement::Let(def) => {
90                let binding = def.name.fragment;
91                ops.push(Op::Sym(binding), def.name.pos);
92                Self::translate_expr(def.value, &mut ops, root);
93                ops.push(Op::Bind, def.pos);
94            }
95            Statement::Output(pos, tok, expr) => {
96                ops.push(Op::Val(Primitive::Str(tok.fragment)), tok.pos);
97                Self::translate_expr(expr, &mut ops, root);
98                ops.push(Op::Runtime(Hook::Out), pos);
99            }
100            Statement::Print(pos, tok, expr) => {
101                ops.push(Op::Val(Primitive::Str(tok.fragment)), tok.pos);
102                Self::translate_expr(expr, &mut ops, root);
103                ops.push(Op::Runtime(Hook::Convert), pos.clone());
104                ops.push(Op::Pop, pos);
105            }
106        }
107    }
108
109    fn translate_stmts(stmts: Vec<Statement>, mut ops: &mut OpsMap, root: &Path) {
110        for stmt in stmts {
111            Self::translate_stmt(stmt, &mut ops, root);
112        }
113    }
114
115    fn translate_expr(expr: Expression, mut ops: &mut OpsMap, root: &Path) {
116        match expr {
117            Expression::Simple(v) => {
118                Self::translate_value(v, &mut ops, root);
119            }
120            Expression::Binary(def) => {
121                match def.kind {
122                    BinaryExprType::Add => {
123                        Self::translate_expr(*def.right, &mut ops, root);
124                        Self::translate_expr(*def.left, &mut ops, root);
125                        ops.push(Op::Add, def.pos);
126                    }
127                    BinaryExprType::Sub => {
128                        Self::translate_expr(*def.right, &mut ops, root);
129                        Self::translate_expr(*def.left, &mut ops, root);
130                        ops.push(Op::Sub, def.pos);
131                    }
132                    BinaryExprType::Div => {
133                        Self::translate_expr(*def.right, &mut ops, root);
134                        Self::translate_expr(*def.left, &mut ops, root);
135                        ops.push(Op::Div, def.pos);
136                    }
137                    BinaryExprType::Mul => {
138                        Self::translate_expr(*def.right, &mut ops, root);
139                        Self::translate_expr(*def.left, &mut ops, root);
140                        ops.push(Op::Mul, def.pos);
141                    }
142                    BinaryExprType::Equal => {
143                        Self::translate_expr(*def.right, &mut ops, root);
144                        Self::translate_expr(*def.left, &mut ops, root);
145                        ops.push(Op::Equal, def.pos);
146                    }
147                    BinaryExprType::GT => {
148                        Self::translate_expr(*def.right, &mut ops, root);
149                        Self::translate_expr(*def.left, &mut ops, root);
150                        ops.push(Op::Gt, def.pos);
151                    }
152                    BinaryExprType::LT => {
153                        Self::translate_expr(*def.right, &mut ops, root);
154                        Self::translate_expr(*def.left, &mut ops, root);
155                        ops.push(Op::Lt, def.pos);
156                    }
157                    BinaryExprType::GTEqual => {
158                        Self::translate_expr(*def.right, &mut ops, root);
159                        Self::translate_expr(*def.left, &mut ops, root);
160                        ops.push(Op::GtEq, def.pos);
161                    }
162                    BinaryExprType::LTEqual => {
163                        Self::translate_expr(*def.right, &mut ops, root);
164                        Self::translate_expr(*def.left, &mut ops, root);
165                        ops.push(Op::LtEq, def.pos);
166                    }
167                    BinaryExprType::NotEqual => {
168                        Self::translate_expr(*def.right, &mut ops, root);
169                        Self::translate_expr(*def.left, &mut ops, root);
170                        ops.push(Op::Equal, def.pos.clone());
171                        ops.push(Op::Not, def.pos);
172                    }
173                    BinaryExprType::REMatch => {
174                        Self::translate_expr(*def.right, &mut ops, root);
175                        Self::translate_expr(*def.left, &mut ops, root);
176                        ops.push(Op::Runtime(Hook::Regex), def.pos);
177                    }
178                    BinaryExprType::NotREMatch => {
179                        Self::translate_expr(*def.right, &mut ops, root);
180                        Self::translate_expr(*def.left, &mut ops, root);
181                        ops.push(Op::Runtime(Hook::Regex), def.pos.clone());
182                        ops.push(Op::Not, def.pos);
183                    }
184                    BinaryExprType::IS => {
185                        Self::translate_expr(*def.right, &mut ops, root);
186                        Self::translate_expr(*def.left, &mut ops, root);
187                        ops.push(Op::Typ, def.pos.clone());
188                        ops.push(Op::Equal, def.pos);
189                    }
190                    BinaryExprType::AND => {
191                        Self::translate_expr(*def.left, &mut ops, root);
192                        ops.push(Op::Noop, def.pos);
193                        let idx = ops.len() - 1;
194                        Self::translate_expr(*def.right, &mut ops, root);
195                        let jptr = (ops.len() - 1 - idx) as i32;
196                        ops.replace(idx, Op::And(jptr));
197                    }
198                    BinaryExprType::OR => {
199                        Self::translate_expr(*def.left, &mut ops, root);
200                        ops.push(Op::Noop, def.pos); // Placeholder
201                        let idx = ops.len() - 1;
202                        Self::translate_expr(*def.right, &mut ops, root);
203                        let jptr = (ops.len() - 1 - idx) as i32;
204                        ops.replace(idx, Op::Or(jptr));
205                    }
206                    BinaryExprType::Mod => {
207                        Self::translate_expr(*def.right, &mut ops, root);
208                        Self::translate_expr(*def.left, &mut ops, root);
209                        ops.push(Op::Mod, def.pos);
210                    }
211                    BinaryExprType::IN => {
212                        // Dot expressions expect the right side to be pushed first
213                        Self::translate_expr(*def.right.clone(), &mut ops, root);
214                        // Symbols on the left side should be converted to strings to satisfy
215                        // the Index operation contract.
216                        match *def.left.clone() {
217                            Expression::Simple(Value::Symbol(name)) => {
218                                // We really just want an expression that turns a symbol
219                                // into a name if the subject is a tuple and doesn't
220                                // otherwise
221                                let new_expr = Expression::Select(SelectDef {
222                                    val: Box::new(Expression::Binary(BinaryOpDef {
223                                        kind: BinaryExprType::IS,
224                                        right: Box::new(Expression::Simple(Value::Str(
225                                            PositionedItem::new(
226                                                "tuple".to_owned(),
227                                                def.left.pos().clone(),
228                                            ),
229                                        ))),
230                                        left: def.right.clone(),
231                                        pos: def.left.pos().clone(),
232                                    })),
233                                    default: Some(Box::new(Expression::Simple(Value::Symbol(
234                                        name.clone(),
235                                    )))),
236                                    tuple: vec![(
237                                        Token::new("true", TokenType::BAREWORD, def.right.pos()),
238                                        Expression::Simple(Value::Str(name)),
239                                    )],
240                                    pos: def.left.pos().clone(),
241                                });
242                                Self::translate_expr(new_expr, &mut ops, root);
243                            }
244                            expr => {
245                                Self::translate_expr(expr, &mut ops, root);
246                            }
247                        }
248                        ops.push(Op::Exist, def.pos.clone());
249                    }
250                    BinaryExprType::DOT => {
251                        // Symbols on the right side should be converted to strings to satisfy
252                        // the Index operation contract.
253                        match *def.right {
254                            Expression::Copy(copy_def) => {
255                                // Dot expressions expect the left side to be pushed first
256                                Self::translate_expr(*def.left, &mut ops, root);
257                                // first handle the selector
258                                match copy_def.selector {
259                                    Value::Str(sym) | Value::Symbol(sym) => {
260                                        ops.push(Op::Val(Primitive::Str(sym.val)), sym.pos);
261                                    }
262                                    Value::Int(sym) => {
263                                        ops.push(Op::Val(Primitive::Int(sym.val)), sym.pos);
264                                    }
265                                    _ => unreachable!(),
266                                }
267                                ops.push(Op::Index, copy_def.pos.clone());
268                                Self::translate_copy(ops, copy_def.fields, copy_def.pos, root);
269                                return;
270                            }
271                            Expression::Call(call_def) => {
272                                // first push our arguments.
273                                let count = call_def.arglist.len() as i64;
274                                for e in call_def.arglist {
275                                    Self::translate_expr(e, &mut ops, root);
276                                }
277                                ops.push(Op::Val(Primitive::Int(count)), call_def.pos.clone());
278                                // Dot expressions expect the left side to be pushed first
279                                Self::translate_expr(*def.left, &mut ops, root);
280                                // then handle the selector
281                                let func_pos = call_def.funcref.pos().clone();
282                                match call_def.funcref {
283                                    Value::Str(sym) | Value::Symbol(sym) => {
284                                        ops.push(Op::Val(Primitive::Str(sym.val)), sym.pos);
285                                    }
286                                    Value::Int(sym) => {
287                                        ops.push(Op::Val(Primitive::Int(sym.val)), sym.pos);
288                                    }
289                                    _ => unreachable!(),
290                                }
291                                ops.push(Op::Index, def.pos);
292                                ops.push(Op::FCall, func_pos);
293                                return;
294                            }
295                            Expression::Simple(Value::Symbol(name)) => {
296                                // Dot expressions expect the left side to be pushed first
297                                Self::translate_expr(*def.left, &mut ops, root);
298                                Self::translate_expr(
299                                    Expression::Simple(Value::Str(name)),
300                                    &mut ops,
301                                    root,
302                                );
303                            }
304                            expr => {
305                                // Dot expressions expect the left side to be pushed first
306                                Self::translate_expr(*def.left, &mut ops, root);
307                                Self::translate_expr(expr, &mut ops, root);
308                            }
309                        }
310                        ops.push(Op::Index, def.pos);
311                    }
312                };
313            }
314            Expression::Grouped(expr, _) => {
315                Self::translate_expr(*expr, &mut ops, root);
316            }
317            Expression::Fail(def) => {
318                let msg_pos = def.message.pos().clone();
319                Self::translate_expr(*def.message, &mut ops, root);
320                ops.push(Op::Val(Primitive::Str("UserDefined: ".to_owned())), msg_pos);
321                ops.push(Op::Add, def.pos.clone());
322                ops.push(Op::Bang, def.pos);
323            }
324            Expression::Format(def) => {
325                match def.args {
326                    FormatArgs::List(mut elems) => {
327                        let formatter = SimpleTemplate::new();
328                        // TODO(jwall): This really belongs in a preprocess step
329                        // before here.
330                        let mut parts = formatter.parse(&def.template).unwrap();
331                        // We need to push process these in reverse order for the
332                        // vm to process things correctly;
333                        elems.reverse();
334                        parts.reverse();
335                        let mut elems_iter = elems.drain(0..);
336                        let mut parts_iter = parts.drain(0..);
337                        Self::translate_template_part(
338                            def.pos.clone(),
339                            parts_iter.next().unwrap(),
340                            &mut elems_iter,
341                            &mut ops,
342                            true,
343                            root,
344                        );
345                        for p in parts_iter {
346                            Self::translate_template_part(
347                                def.pos.clone(),
348                                p,
349                                &mut elems_iter,
350                                &mut ops,
351                                true,
352                                root,
353                            );
354                            // TODO(jwall): We could get a little more helpful about where
355                            // these positions are.
356                            ops.push(Op::Add, def.pos.clone());
357                        }
358                    }
359                    FormatArgs::Single(expr) => {
360                        let formatter = ExpressionTemplate::new();
361                        // TODO(jwall): This really belongs in a preprocess step
362                        // before here.
363                        let mut parts = formatter.parse(&def.template).unwrap();
364                        parts.reverse();
365                        let mut parts_iter = parts.drain(0..);
366                        ops.push(Op::Noop, expr.pos().clone());
367                        let scope_idx = ops.len() - 1;
368
369                        // Add our item binding shadowing any binding that already
370                        // existed.
371                        let expr_pos = expr.pos().clone();
372                        ops.push(Op::Sym("item".to_owned()), expr.pos().clone());
373                        Self::translate_expr(*expr, &mut ops, root);
374                        ops.push(Op::BindOver, expr_pos.clone());
375                        let mut elems = Vec::new();
376                        let mut elems_iter = elems.drain(0..);
377                        Self::translate_template_part(
378                            def.pos.clone(),
379                            parts_iter.next().unwrap(),
380                            &mut elems_iter,
381                            &mut ops,
382                            false,
383                            root,
384                        );
385                        for p in parts_iter {
386                            Self::translate_template_part(
387                                def.pos.clone(),
388                                p,
389                                &mut elems_iter,
390                                &mut ops,
391                                false,
392                                root,
393                            );
394                            ops.push(Op::Add, expr_pos.clone());
395                        }
396                        ops.push(Op::Return, expr_pos);
397                        let jump_idx = (ops.len() - 1 - scope_idx) as i32;
398                        ops.replace(scope_idx, Op::NewScope(jump_idx));
399                    }
400                }
401            }
402            Expression::Func(def) => {
403                ops.push(Op::InitList, def.pos.clone());
404                for b in def.argdefs {
405                    // FIXME(jwall): if there is a projection
406                    // then add the projection check here?
407                    ops.push(Op::Sym(b.val), b.pos.clone());
408                    ops.push(Op::Element, b.pos);
409                }
410                ops.push(Op::Noop, def.pos.clone());
411                let idx = ops.len() - 1;
412                Self::translate_expr(*def.fields, &mut ops, root);
413                ops.push(Op::Return, def.pos);
414                let jptr = ops.len() - 1 - idx;
415                ops.replace(idx, Op::Func(jptr as i32));
416            }
417            Expression::FuncOp(def) => {
418                match def {
419                    FuncOpDef::Map(def) => {
420                        // push the function on the stack first.
421                        Self::translate_expr(*def.func, &mut ops, root);
422                        // push the target on the stack third
423                        Self::translate_expr(*def.target, &mut ops, root);
424                        // finally push the Hook::Map opcode
425                        ops.push(Op::Runtime(Hook::Map), def.pos);
426                    }
427                    FuncOpDef::Filter(def) => {
428                        // push the function on the stack first.
429                        Self::translate_expr(*def.func, &mut ops, root);
430                        // push the target on the stack third
431                        Self::translate_expr(*def.target, &mut ops, root);
432                        // finally push the Hook::Map opcode
433                        ops.push(Op::Runtime(Hook::Filter), def.pos);
434                    }
435                    FuncOpDef::Reduce(def) => {
436                        // push the function on the stack first.
437                        Self::translate_expr(*def.func, &mut ops, root);
438                        // push the accumulator on the stack third
439                        Self::translate_expr(*def.acc, &mut ops, root);
440                        // push the target on the stack third
441                        Self::translate_expr(*def.target, &mut ops, root);
442                        // finally push the Hook::Map opcode
443                        ops.push(Op::Runtime(Hook::Reduce), def.pos);
444                    }
445                }
446            }
447            Expression::Import(def) => {
448                let link_path = def.path.fragment.clone();
449                ops.add_link(link_path, def.path.pos.clone());
450                ops.push(Op::Val(Primitive::Str(def.path.fragment)), def.path.pos);
451                ops.push(Op::Runtime(Hook::Import), def.pos);
452            }
453            Expression::Include(def) => {
454                ops.push(Op::Val(Primitive::Str(def.typ.fragment)), def.typ.pos);
455                ops.push(Op::Val(Primitive::Str(def.path.fragment)), def.path.pos);
456                ops.push(Op::Runtime(Hook::Include), def.pos);
457            }
458            Expression::Module(def) => {
459                let argset = def.arg_set;
460                let out_expr = def.out_expr;
461                let stmts = def.statements;
462                // Init our module tuple bindings
463                ops.push(Op::InitTuple, def.pos.clone());
464                for (t, e) in argset {
465                    // FIXME(jwall): if there is a projection
466                    // then add the projection check here?
467                    ops.push(Op::Sym(t.fragment), t.pos.clone());
468                    Self::translate_expr(e, &mut ops, root);
469                    ops.push(Op::Field, t.pos);
470                }
471                // If there is one then emit our return expression
472                if let Some(expr) = out_expr {
473                    // Insert placeholder until we know jptr for this thunk
474                    let expr_pos = expr.pos().clone();
475                    ops.push(Op::Noop, expr.pos().clone());
476                    let idx = ops.len() - 1;
477                    Self::translate_expr(*expr, &mut ops, root);
478                    ops.push(Op::Return, expr_pos.clone());
479                    let jptr = ops.len() - idx - 1;
480                    ops.replace(idx, Op::InitThunk(jptr as i32));
481                }
482                // Insert a placeholder Opcode until we know jptr for the
483                // module.
484                ops.push(Op::Noop, def.pos.clone());
485                let idx = ops.len() - 1;
486                // Bind our mod tuple.
487                ops.push(Op::Bind, def.pos.clone());
488                // emit all of our statements;
489                Self::translate_stmts(stmts, &mut ops, root);
490                // Return from the module
491                ops.push(Op::Return, def.pos);
492                let jptr = ops.len() - idx - 1;
493                ops.replace(idx, Op::Module(jptr as i32));
494            }
495            Expression::Not(def) => {
496                Self::translate_expr(*def.expr, &mut ops, root);
497                ops.push(Op::Not, def.pos);
498            }
499            Expression::Range(def) => {
500                Self::translate_expr(*def.end, &mut ops, root);
501                if let Some(expr) = def.step {
502                    Self::translate_expr(*expr, &mut ops, root);
503                } else {
504                    ops.push(Op::Val(Primitive::Empty), def.pos.clone());
505                }
506                Self::translate_expr(*def.start, &mut ops, root);
507                ops.push(Op::Runtime(Hook::Range), def.pos);
508            }
509            Expression::Select(def) => {
510                let default_pos = def.val.pos().clone();
511                Self::translate_expr(*def.val, &mut ops, root);
512                let mut jumps = Vec::new();
513                for (key, val) in def.tuple {
514                    ops.push(Op::Sym(key.fragment), key.pos.clone());
515                    ops.push(Op::Noop, key.pos);
516                    let idx = ops.len() - 1;
517                    let expr_pos = val.pos().clone();
518                    Self::translate_expr(val, &mut ops, root);
519                    ops.push(Op::Noop, expr_pos);
520                    jumps.push(ops.len() - 1);
521                    let jptr = ops.len() - idx - 1;
522                    ops.replace(idx, Op::SelectJump(jptr as i32));
523                }
524                ops.push(Op::Pop, def.pos.clone());
525                if let Some(default) = def.default {
526                    Self::translate_expr(*default, &mut ops, root);
527                } else {
528                    ops.push(
529                        Op::Val(Primitive::Str(
530                            "Unhandled select case with no default".to_owned(),
531                        )),
532                        default_pos,
533                    );
534                    ops.push(Op::Bang, def.pos);
535                }
536                let end = ops.len() - 1;
537                for i in jumps {
538                    let idx = end - i;
539                    ops.replace(i, Op::Jump(idx as i32));
540                }
541            }
542            Expression::Call(call_def) => {
543                let count = call_def.arglist.len() as i64;
544                for e in call_def.arglist {
545                    Self::translate_expr(e, &mut ops, root);
546                }
547                ops.push(Op::Val(Primitive::Int(count)), call_def.pos.clone());
548                // then push the func reference
549                let func_pos = call_def.funcref.pos().clone();
550                Self::translate_value(call_def.funcref, &mut ops, root);
551                ops.push(Op::FCall, func_pos);
552            }
553            Expression::Cast(cast_def) => {
554                Self::translate_expr(*cast_def.target, &mut ops, root);
555                ops.push(Op::Cast(cast_def.cast_type), cast_def.pos);
556            }
557            Expression::Copy(def) => {
558                Self::translate_value(def.selector, &mut ops, root);
559                Self::translate_copy(ops, def.fields, def.pos, root);
560            }
561            Expression::Debug(def) => {
562                let mut buffer: Vec<u8> = Vec::new();
563                {
564                    let mut printer = crate::ast::printer::AstPrinter::new(2, &mut buffer);
565                    let _ = printer.render_expr(&def.expr);
566                }
567                let expr_pretty = String::from_utf8(buffer).unwrap();
568                ops.push(Op::Val(Primitive::Str(expr_pretty)), def.pos.clone());
569                Self::translate_expr(*def.expr, &mut ops, root);
570                ops.push(Op::Runtime(Hook::Trace(def.pos.clone())), def.pos);
571            }
572        }
573    }
574
575    fn translate_template_part<EI: Iterator<Item = Expression>>(
576        pos: Position,
577        part: TemplatePart,
578        elems: &mut EI,
579        mut ops: &mut OpsMap,
580        place_holder: bool,
581        root: &Path,
582    ) {
583        match part {
584            TemplatePart::Str(s) => {
585                ops.push(Op::Val(Primitive::Str(s.into_iter().collect())), pos);
586            }
587            TemplatePart::PlaceHolder(_idx) => {
588                if !place_holder {
589                    // In theory this should never be reachable
590                    unreachable!();
591                } else {
592                    Self::translate_expr(elems.next().unwrap(), &mut ops, root);
593                    ops.push(Op::Render, pos);
594                }
595            }
596            TemplatePart::Expression(expr) => {
597                if place_holder {
598                    unreachable!();
599                } else {
600                    Self::translate_expr(expr, &mut ops, root);
601                    ops.push(Op::Render, pos);
602                }
603            }
604        }
605    }
606
607    fn translate_copy(
608        mut ops: &mut OpsMap,
609        flds: Vec<(Token, Expression)>,
610        pos: Position,
611        root: &Path,
612    ) {
613        ops.push(Op::PushSelf, pos.clone());
614        ops.push(Op::InitTuple, pos.clone());
615        for (t, e) in flds {
616            ops.push(Op::Sym(t.fragment), t.pos.clone());
617            Self::translate_expr(e, &mut ops, root);
618            ops.push(Op::Field, t.pos.clone());
619        }
620        ops.push(Op::Cp, pos.clone());
621        ops.push(Op::PopSelf, pos);
622    }
623
624    fn translate_value(value: Value, mut ops: &mut OpsMap, root: &Path) {
625        match value {
626            Value::Int(i) => ops.push(Op::Val(Primitive::Int(i.val)), i.pos),
627            Value::Float(f) => ops.push(Op::Val(Primitive::Float(f.val)), f.pos),
628            Value::Str(s) => ops.push(Op::Val(Primitive::Str(s.val)), s.pos),
629            Value::Empty(pos) => ops.push(Op::Val(Primitive::Empty), pos),
630            Value::Boolean(b) => ops.push(Op::Val(Primitive::Bool(b.val)), b.pos),
631            Value::Symbol(s) => {
632                ops.push(Op::DeRef(s.val), s.pos);
633            }
634            Value::Tuple(flds) => {
635                ops.push(Op::InitTuple, flds.pos);
636                for (k, v) in flds.val {
637                    ops.push(Op::Sym(k.fragment), k.pos.clone());
638                    Self::translate_expr(v, &mut ops, root);
639                    ops.push(Op::Field, k.pos.clone());
640                }
641            }
642            Value::List(els) => {
643                ops.push(Op::InitList, els.pos);
644                for el in els.elems {
645                    let el_pos = el.pos().clone();
646                    Self::translate_expr(el, &mut ops, root);
647                    ops.push(Op::Element, el_pos);
648                }
649            }
650        }
651    }
652}