compiler.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. use std::collections::HashMap;
  2. use crate::parser::{SchemaCode, SchemaWitness};
  3. use crate::state::{Constants, Line};
  4. use crate::types::{FuncFormat, TypeId};
  5. #[derive(Debug, Clone)]
  6. pub struct CodeLine {
  7. pub func_format: FuncFormat,
  8. pub return_values: Vec<String>,
  9. pub args: Vec<String>,
  10. pub arg_idxs: Vec<usize>,
  11. pub code_line: Line,
  12. }
  13. impl CodeLine {
  14. pub fn new(
  15. func_format: FuncFormat,
  16. return_values: Vec<String>,
  17. args: Vec<String>,
  18. arg_idxs: Vec<usize>,
  19. code_line: Line,
  20. ) -> Self {
  21. CodeLine {
  22. func_format,
  23. return_values,
  24. args,
  25. arg_idxs,
  26. code_line,
  27. }
  28. }
  29. }
  30. fn alloc(
  31. stacks: &mut Vec<Vec<String>>,
  32. stack_vars: &mut HashMap<String, (TypeId, usize)>,
  33. variable: String,
  34. type_id: TypeId,
  35. ) {
  36. assert!(type_id as usize <= stacks.len());
  37. let idx = stacks[type_id as usize].len();
  38. // Add variable to the stack for its TypeId
  39. stacks[type_id as usize].push(variable.clone());
  40. // Create mapping from variable name
  41. stack_vars.insert(variable, (type_id, idx));
  42. }
  43. pub struct Compiler {
  44. pub witness: SchemaWitness,
  45. pub uncompiled_code: SchemaCode,
  46. pub constants: Constants,
  47. }
  48. impl Compiler {
  49. pub fn new(witness: SchemaWitness, uncompiled_code: SchemaCode, constants: Constants) -> Self {
  50. Compiler {
  51. witness,
  52. uncompiled_code,
  53. constants,
  54. }
  55. }
  56. pub fn compile(&self) -> Vec<CodeLine> {
  57. let mut code = vec![];
  58. // Each unique TypeID has its own stack
  59. let mut stacks = vec![];
  60. let mut stack: Vec<String>;
  61. for _ in 0..TypeId::LastId as usize {
  62. stack = vec![];
  63. stacks.push(stack);
  64. }
  65. // Map from variable name to stacks above
  66. let mut stack_vars = HashMap::new();
  67. // Load constants
  68. for variable in self.constants.variables() {
  69. let type_id = self.constants.lookup(variable.to_string());
  70. alloc(&mut stacks, &mut stack_vars, variable.to_string(), type_id);
  71. }
  72. // Preload stack with our witness values
  73. for (type_id, variable, _line) in self.witness.clone() {
  74. alloc(&mut stacks, &mut stack_vars, variable.to_string(), type_id);
  75. }
  76. for (func_format, retvals, args, code_line) in &self.uncompiled_code {
  77. assert!(args.len() == func_format.param_types.len());
  78. let mut arg_idxs = vec![];
  79. // Loop through all arguments
  80. for (variable, type_id) in args.iter().zip(func_format.param_types.iter()) {
  81. assert!(*type_id as usize <= stacks.len());
  82. assert!(stack_vars.contains_key(variable));
  83. // Find the index for the M by N matrix of our variable
  84. let (loc_type_id, loc_idx) = stack_vars.get(variable).unwrap();
  85. assert!(type_id == loc_type_id);
  86. assert!(&stacks[*loc_type_id as usize][*loc_idx as usize] == variable);
  87. // This is the info to be serialized, not the variable names
  88. arg_idxs.push(*loc_idx);
  89. }
  90. assert!(retvals.len() == func_format.return_type_ids.len());
  91. for (retval, ret_id) in retvals.iter().zip(func_format.return_type_ids.iter()) {
  92. // Allocate returned values so they can be used by
  93. // subsequent function calls.
  94. alloc(&mut stacks, &mut stack_vars, retval.to_string(), *ret_id);
  95. }
  96. code.push(CodeLine::new(
  97. func_format.clone(),
  98. retvals.clone(),
  99. args.clone(),
  100. arg_idxs,
  101. code_line.clone(),
  102. ));
  103. }
  104. code
  105. }
  106. }
  107. #[derive(Debug, Clone)]
  108. pub struct CompiledContract {
  109. pub name: String,
  110. pub witness: SchemaWitness,
  111. pub code: Vec<CodeLine>,
  112. }
  113. impl CompiledContract {
  114. pub fn new(name: String, witness: SchemaWitness, code: Vec<CodeLine>) -> Self {
  115. CompiledContract {
  116. name,
  117. witness,
  118. code,
  119. }
  120. }
  121. }