1use super::ast::*;
2use super::ArgSpec;
3use super::ArithmeticBinop;
4use super::BasicError;
5use super::Binop;
6use super::Code;
7use super::Opcode;
8use super::RcStr;
9use super::VarScope;
10use super::PRELUDE_NAME;
11use std::collections::HashMap;
12use std::collections::HashSet;
13use std::rc::Rc;
14
15pub fn translate_files(mut files: Vec<File>) -> Result<Code, BasicError> {
16 let mut global_vars = Vars::new();
19 for file in &mut files {
20 prepare_vars_for_file(&mut global_vars, file)?;
21 }
22
23 let mut scope = Scope::new();
25 for file in &files {
26 for imp in &file.imports {
27 scope.decl(Item::Import(imp.clone()))?;
28 }
29 }
30 for var in &global_vars.list {
31 scope.decl(Item::Var(var.clone()))?;
32 }
33
34 let mut code = Code::new(
35 false,
36 format!("[main]").into(),
37 ArgSpec::empty(),
38 global_vars.list,
39 );
40
41 for file in &files {
44 scope.file_name = file.name().clone();
45 for func in &file.funcs {
46 let func_code = translate_func(&mut scope, func)?;
47 code.add(Opcode::NewFunc(Rc::new(func_code)), func.mark.clone());
48 if func.test {
49 code.add(Opcode::AddToTest, func.mark.clone());
50 }
51 let var = func.as_var.as_ref().unwrap();
52 code.add(Opcode::Set(var.vscope, var.index), func.mark.clone());
53 }
54 }
55
56 for file in &files {
58 scope.file_name = file.name().clone();
59 translate_stmt(&mut code, &mut scope, &file.body)?;
60 }
61
62 code.resolve_labels()?;
63
64 Ok(code)
65}
66
67struct Vars {
68 list: Vec<Var>,
69 map: HashMap<RcStr, Var>,
70}
71
72impl Vars {
73 fn new() -> Self {
74 Self {
75 list: vec![],
76 map: HashMap::new(),
77 }
78 }
79 fn add(&mut self, var: Var) {
80 if !self.map.contains_key(&var.name) {
81 self.force_add(var).unwrap();
82 }
83 }
84 fn force_add(&mut self, var: Var) -> Result<(), BasicError> {
85 assert_eq!(self.list.len(), self.map.len());
86 if let Some(oldvar) = self.map.get(&var.name) {
87 Err(BasicError::new_with_help(
88 vec![var.mark.clone(), oldvar.mark.clone()],
89 format!("Conflicting definitions of {}", var.name),
90 format!(concat!(
91 "To reduce the chance of confusion, it is considered an ",
92 "error for a function to share a name with a normal variable ",
93 "or even another function.",
94 )),
95 ))
96 } else {
97 self.map.insert(var.name.clone(), var.clone());
98 self.list.push(var);
99 Ok(())
100 }
101 }
102 fn len(&self) -> usize {
103 assert_eq!(self.list.len(), self.map.len());
104 self.list.len()
105 }
106}
107
108fn prepare_vars_for_file(out: &mut Vars, file: &mut File) -> Result<(), BasicError> {
109 let file_name = file.name().clone();
110
111 for imp in &mut file.imports {
112 imp.unique_name = format!("{}#{}", file_name, imp.alias).into();
113 }
114
115 prepare_vars_for_stmt(out, &mut file.body, Some(&file_name))?;
116
117 for func in &mut file.funcs {
125 prepare_vars_for_func(func)?;
126 let var = mkvar(
127 func.mark.clone(),
128 &func.short_name,
129 Some(&file_name),
130 out.len(),
131 );
132 func.as_var = Some(var.clone());
133 out.force_add(var)?;
134 }
135
136 Ok(())
137}
138
139fn prepare_vars_for_func(func: &mut FuncDisplay) -> Result<(), BasicError> {
140 let mut vars = Vars::new();
141 let spec = &func.argspec;
142 for param in &spec.req {
143 let var = mkvar(func.mark.clone(), param, None, vars.len());
144 vars.force_add(var)?;
145 }
146 for (param, _) in &spec.def {
147 let var = mkvar(func.mark.clone(), param, None, vars.len());
148 vars.force_add(var)?;
149 }
150 if let Some(param) = &spec.var {
151 let var = mkvar(func.mark.clone(), param, None, vars.len());
152 vars.force_add(var)?;
153 }
154 prepare_vars_for_stmt(&mut vars, &mut func.body, None)?;
155 func.vars = vars.list;
156 Ok(())
157}
158
159fn prepare_vars_for_stmt(
160 out: &mut Vars,
161 stmt: &mut Stmt,
162 prefix: Option<&RcStr>,
163) -> Result<(), BasicError> {
164 match &mut stmt.desc {
165 StmtDesc::Block(stmts) => {
166 for stmt in stmts {
167 prepare_vars_for_stmt(out, stmt, prefix)?;
168 }
169 }
170 StmtDesc::Assign(target, other_targets, _) => {
171 prepare_vars_for_target(out, target, prefix)?;
172 for target in other_targets {
173 prepare_vars_for_target(out, target, prefix)?;
174 }
175 }
176 StmtDesc::If(pairs, other) => {
177 for (_cond, body) in pairs {
178 prepare_vars_for_stmt(out, body, prefix)?;
179 }
180 if let Some(other) = other {
181 prepare_vars_for_stmt(out, other, prefix)?;
182 }
183 }
184 StmtDesc::While(_cond, body) => {
185 prepare_vars_for_stmt(out, body, prefix)?;
186 }
187 StmtDesc::ForIn(target, _container, body) => {
188 prepare_vars_for_target(out, target, prefix)?;
189 prepare_vars_for_stmt(out, body, prefix)?;
190 }
191 StmtDesc::ForClassic(target, _start, _end, _inclusive, _step, body) => {
192 prepare_vars_for_target(out, target, prefix)?;
193 prepare_vars_for_stmt(out, body, prefix)?;
194 }
195 StmtDesc::Print(_)
196 | StmtDesc::Assert(_)
197 | StmtDesc::Expr(_)
198 | StmtDesc::Return(_)
199 | StmtDesc::Label(_)
200 | StmtDesc::Goto(_) => {}
201 }
202 Ok(())
203}
204
205fn prepare_vars_for_target(
206 out: &mut Vars,
207 target: &AssignTarget,
208 prefix: Option<&RcStr>,
209) -> Result<(), BasicError> {
210 match &target.desc {
211 AssignTargetDesc::Name(name) => {
212 out.add(mkvar(target.mark.clone(), name, prefix, out.len()));
213 }
214 AssignTargetDesc::List(list) => {
215 for subtarget in list {
216 prepare_vars_for_target(out, subtarget, prefix)?;
217 }
218 }
219 }
220 Ok(())
221}
222
223fn mkvar(mark: Mark, name: &RcStr, file_name: Option<&RcStr>, index: usize) -> Var {
224 let index = index as u32;
225 if let Some(file_name) = file_name {
226 Var {
227 mark: mark,
228 name: format!("{}#{}", file_name, name).into(),
229 vscope: VarScope::Global,
230 index,
231 }
232 } else {
233 Var {
234 mark: mark,
235 name: name.clone(),
236 vscope: VarScope::Local,
237 index,
238 }
239 }
240}
241
242fn translate_func(scope: &mut Scope, func: &FuncDisplay) -> Result<Code, BasicError> {
243 let mut code = Code::new(
244 func.generator,
245 func.full_name().clone(),
246 func.argspec.clone(),
247 func.vars.clone(),
248 );
249 scope.enter_local();
250 for var in &func.vars {
251 scope.decl(Item::Var(var.clone()))?;
252 }
253 translate_stmt(&mut code, scope, &func.body)?;
254 scope.exit_local();
255 code.resolve_labels()?;
256 Ok(code)
257}
258
259fn translate_stmt(code: &mut Code, scope: &mut Scope, stmt: &Stmt) -> Result<(), BasicError> {
260 match &stmt.desc {
261 StmtDesc::Block(stmts) => {
262 for child_stmt in stmts {
263 translate_stmt(code, scope, child_stmt)?;
264 }
265 }
266 StmtDesc::Return(expr) => {
267 if let Some(expr) = expr {
268 translate_expr(code, scope, expr)?;
269 } else {
270 code.add(Opcode::Nil, stmt.mark.clone());
271 }
272 code.add(Opcode::Return, stmt.mark.clone());
273 }
274 StmtDesc::Assign(target, other_targets, expr) => {
275 translate_expr(code, scope, expr)?;
276 for target in other_targets.iter().rev() {
277 translate_assign(code, scope, target, false)?;
278 }
279 translate_assign(code, scope, target, true)?;
280 }
281 StmtDesc::Expr(expr) => {
282 translate_expr(code, scope, expr)?;
283 code.add(Opcode::Pop, stmt.mark.clone());
284 }
285 StmtDesc::Print(arg) => {
286 translate_expr(code, scope, arg)?;
287 code.add(Opcode::Print, stmt.mark.clone());
288 }
289 StmtDesc::Assert(arg) => match &arg.desc {
290 ExprDesc::Binop(Binop::Equal, lhs, rhs) => {
291 translate_expr(code, scope, lhs)?;
292 translate_expr(code, scope, rhs)?;
293 code.add(Opcode::AssertEq, stmt.mark.clone());
294 }
295 _ => {
296 translate_expr(code, scope, arg)?;
297 code.add(Opcode::Assert, stmt.mark.clone());
298 }
299 },
300 StmtDesc::Label(label) => {
301 code.add(Opcode::Label(label.clone()), stmt.mark.clone());
302 }
303 StmtDesc::Goto(label) => {
304 code.add(Opcode::UnresolvedGoto(label.clone()), stmt.mark.clone());
305 }
306 StmtDesc::If(pairs, other) => {
307 let end_label = scope.new_label();
308 for (cond, body) in pairs {
309 let next_label = scope.new_label();
310 translate_expr(code, scope, cond)?;
311 code.add(
312 Opcode::UnresolvedGotoIfFalse(next_label.clone()),
313 cond.mark.clone(),
314 );
315 translate_stmt(code, scope, body)?;
316 code.add(Opcode::UnresolvedGoto(end_label.clone()), body.mark.clone());
317 code.add(Opcode::Label(next_label), cond.mark.clone());
318 }
319 if let Some(other) = other {
320 translate_stmt(code, scope, other)?;
321 }
322 code.add(Opcode::Label(end_label), stmt.mark.clone());
323 }
324 StmtDesc::While(cond, body) => {
325 let start_label = scope.new_label();
326 let end_label = scope.new_label();
327 code.add(Opcode::Label(start_label.clone()), stmt.mark.clone());
328 translate_expr(code, scope, cond)?;
329 code.add(
330 Opcode::UnresolvedGotoIfFalse(end_label.clone()),
331 cond.mark.clone(),
332 );
333 translate_stmt(code, scope, body)?;
334 code.add(Opcode::UnresolvedGoto(start_label), stmt.mark.clone());
335 code.add(Opcode::Label(end_label), stmt.mark.clone());
336 }
337 StmtDesc::ForIn(target, container, body) => {
338 let start_label = scope.new_label();
339 let end_label = scope.new_label();
340
341 translate_expr(code, scope, container)?;
342
343 code.add(Opcode::Label(start_label.clone()), stmt.mark.clone());
344 code.add(Opcode::Next, stmt.mark.clone());
345 code.add(
346 Opcode::UnresolvedGotoIfFalse(end_label.clone()),
347 stmt.mark.clone(),
348 );
349
350 translate_assign(code, scope, target, true)?;
351 translate_stmt(code, scope, body)?;
352 code.add(Opcode::UnresolvedGoto(start_label), stmt.mark.clone());
353
354 code.add(Opcode::Label(end_label), stmt.mark.clone());
355 code.add(Opcode::Pop, stmt.mark.clone()); code.add(Opcode::Pop, stmt.mark.clone()); }
358 StmtDesc::ForClassic(target, start, end, inclusive, step, body) => {
359 let start_label = scope.new_label();
360 let end_label = scope.new_label();
361
362 translate_expr(code, scope, end)?;
363 translate_expr(code, scope, start)?;
364
365 code.add(Opcode::Label(start_label.clone()), stmt.mark.clone());
366
367 code.add(Opcode::Dup2, stmt.mark.clone());
370 code.add(
371 Opcode::Binop(if *step < 0.0 {
372 if *inclusive {
373 Binop::LessThanOrEqual
374 } else {
375 Binop::LessThan
376 }
377 } else if *step > 0.0 {
378 if *inclusive {
379 Binop::GreaterThanOrEqual
380 } else {
381 Binop::GreaterThan
382 }
383 } else {
384 return Err(BasicError::new(
385 vec![stmt.mark.clone()],
386 format!("The STEP of a FOR loop cannot be zero"),
387 ));
388 }),
389 stmt.mark.clone(),
390 );
391 code.add(
392 Opcode::UnresolvedGotoIfFalse(end_label.clone()),
393 stmt.mark.clone(),
394 );
395
396 translate_assign(code, scope, target, false)?;
398
399 translate_stmt(code, scope, body)?;
400
401 code.add(Opcode::Number(*step), stmt.mark.clone());
402 code.add(
403 Opcode::Binop(Binop::Arithmetic(ArithmeticBinop::Add)),
404 stmt.mark.clone(),
405 );
406 code.add(Opcode::UnresolvedGoto(start_label), stmt.mark.clone());
407
408 code.add(Opcode::Label(end_label), stmt.mark.clone());
409 code.add(Opcode::Pop, stmt.mark.clone()); code.add(Opcode::Pop, stmt.mark.clone()); }
412 }
413 Ok(())
414}
415
416fn translate_assign(
419 code: &mut Code,
420 scope: &mut Scope,
421 target: &AssignTarget,
422 consume: bool,
423) -> Result<(), BasicError> {
424 match &target.desc {
425 AssignTargetDesc::Name(name) => {
426 let var = scope.getvar_or_error(&target.mark, name)?;
427 if consume {
428 code.add(Opcode::Set(var.vscope, var.index), target.mark.clone());
429 } else {
430 code.add(Opcode::Tee(var.vscope, var.index), target.mark.clone());
431 }
432 }
433 AssignTargetDesc::List(list) => {
434 if !consume {
435 code.add(Opcode::Dup, target.mark.clone());
436 }
437 code.add(Opcode::Unpack(list.len() as u32), target.mark.clone());
438 for subtarget in list.iter().rev() {
439 translate_assign(code, scope, subtarget, true)?;
440 }
441 }
442 }
443 Ok(())
444}
445
446fn translate_expr(code: &mut Code, scope: &mut Scope, expr: &Expr) -> Result<(), BasicError> {
447 match &expr.desc {
448 ExprDesc::Nil => code.add(Opcode::Nil, expr.mark.clone()),
449 ExprDesc::Bool(x) => code.add(Opcode::Bool(*x), expr.mark.clone()),
450 ExprDesc::Number(x) => code.add(Opcode::Number(*x), expr.mark.clone()),
451 ExprDesc::String(x) => code.add(Opcode::String(x.clone()), expr.mark.clone()),
452 ExprDesc::List(items) => {
453 for item in items {
454 translate_expr(code, scope, item)?;
455 }
456 code.add(Opcode::MakeList(items.len() as u32), expr.mark.clone());
457 }
458 ExprDesc::GetVar(name) => {
459 let var = scope.getvar_or_error(&expr.mark, name)?;
460 code.add(Opcode::Get(var.vscope, var.index), expr.mark.clone());
461 }
462 ExprDesc::GetAttr(owner, attr) => {
463 let imp = match &owner.desc {
464 ExprDesc::GetVar(owner_name) => match scope.rget(owner_name) {
465 Some(Item::Import(imp)) => Some(imp),
466 _ => None,
467 },
468 _ => None,
469 };
470 if let Some(imp) = imp {
471 let full_name = format!("{}#{}", imp.module_name, attr);
473 let var = scope.getvar_or_error(&expr.mark, &full_name)?;
474 code.add(Opcode::Get(var.vscope, var.index), expr.mark.clone());
475 } else {
476 return Err(BasicError::new(
478 vec![expr.mark.clone()],
479 format!("Attribute access not yet supported"),
480 ));
481 }
482 }
483 ExprDesc::CallFunc(f, args) => {
484 translate_expr(code, scope, f)?;
485 for arg in args {
486 translate_expr(code, scope, arg)?;
487 }
488 code.add(Opcode::CallFunc(args.len() as u32), expr.mark.clone());
489 }
490 ExprDesc::Binop(binop, lhs, rhs) => {
491 translate_expr(code, scope, lhs)?;
492 translate_expr(code, scope, rhs)?;
493 code.add(Opcode::Binop(*binop), expr.mark.clone());
494 }
495 ExprDesc::Unop(unop, subexpr) => {
496 translate_expr(code, scope, subexpr)?;
497 code.add(Opcode::Unop(*unop), expr.mark.clone());
498 }
499 ExprDesc::Yield(yieldexpr) => {
500 translate_expr(code, scope, yieldexpr)?;
501 code.add(Opcode::Yield, expr.mark.clone());
502 }
503 ExprDesc::Next(genexpr) => {
504 translate_expr(code, scope, genexpr)?;
505 code.add(Opcode::Next, expr.mark.clone());
506 code.add(Opcode::MakeList(2), expr.mark.clone());
507 }
508 ExprDesc::Disasm(fexpr) => {
509 translate_expr(code, scope, fexpr)?;
510 code.add(Opcode::Disasm, expr.mark.clone());
511 }
512 }
513 Ok(())
514}
515
516struct Scope {
517 file_name: RcStr,
518 globals: HashMap<RcStr, Item>,
519 locals: Option<HashMap<RcStr, Item>>,
520 labels: Vec<HashSet<RcStr>>,
521}
522
523impl Scope {
524 pub fn new() -> Self {
525 Self {
526 file_name: "".to_owned().into(),
527 globals: HashMap::new(),
528 locals: None,
529 labels: vec![HashSet::new()],
530 }
531 }
532 pub fn decl(&mut self, item: Item) -> Result<(), BasicError> {
533 let map = if let Some(locals) = &mut self.locals {
534 locals
535 } else {
536 &mut self.globals
537 };
538 if let Some(old_item) = map.get(item.name()) {
539 Err(BasicError::new(
540 vec![old_item.mark().clone(), item.mark().clone()],
541 format!("{:?} is defined more than once", item.name()),
542 ))
543 } else {
544 map.insert(item.name().clone(), item);
545 Ok(())
546 }
547 }
548 pub fn getvar_or_error(&self, mark: &Mark, name: &str) -> Result<&Var, BasicError> {
549 match self.rget(name) {
550 None => Err(BasicError::new(
551 vec![mark.clone()],
552 format!("Variable {:?} not found", name),
553 )),
554 Some(Item::Import(..)) => Err(BasicError::new(
555 vec![mark.clone()],
556 format!("{:?} is an import, not a variable", name),
557 )),
558 Some(Item::Var(var)) => Ok(var),
559 }
560 }
561 pub fn rget(&self, name: &str) -> Option<&Item> {
562 self.qget(name)
563 .or_else(|| self.qget(&format!("{}#{}", self.file_name, name)))
564 .or_else(|| self.qget(&format!("{}#{}", PRELUDE_NAME, name)))
565 }
566 pub fn qget(&self, qualified_name: &str) -> Option<&Item> {
567 self.locals
568 .as_ref()
569 .and_then(|locals| locals.get(qualified_name))
570 .or_else(|| self.globals.get(qualified_name))
571 }
572 pub fn new_label(&mut self) -> RcStr {
573 let name: RcStr = format!("#{}", self.labels().len()).into();
574 assert!(!self.labels().contains(&name));
575 self.labels_mut().insert(name.clone());
576 name
577 }
578 pub fn enter_local(&mut self) {
579 if self.locals.is_some() {
580 panic!("Scope::enter_local: already in local scope");
581 }
582 self.locals = Some(HashMap::new());
583 self.labels.push(HashSet::new());
584 }
585 pub fn exit_local(&mut self) {
586 if self.locals.is_none() {
587 panic!("Scope::exit_local: not in local scope");
588 }
589 self.locals = None;
590 self.labels.pop().unwrap();
591 }
592 pub fn labels(&self) -> &HashSet<RcStr> {
593 self.labels.last().unwrap()
594 }
595 pub fn labels_mut(&mut self) -> &mut HashSet<RcStr> {
596 self.labels.last_mut().unwrap()
597 }
598}
599
600#[derive(Debug)]
601enum Item {
602 Var(Var),
603 Import(Import),
604}
605
606impl Item {
607 pub fn mark(&self) -> &Mark {
608 match self {
609 Self::Var(var) => &var.mark,
610 Self::Import(imp) => &imp.mark,
611 }
612 }
613 pub fn name(&self) -> &RcStr {
614 match self {
615 Self::Var(var) => &var.name,
616 Self::Import(imp) => &imp.unique_name,
617 }
618 }
619}