Skip to main content

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