variables.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. use super::{Contract, ContractVariable, Symbol};
  2. use output::Output;
  3. use parser::ast;
  4. use resolver::cfg::{cast, expression, set_contract_storage, ControlFlowGraph, Instr, Vartable};
  5. use resolver::ContractVariableType;
  6. pub fn contract_variables(
  7. def: &ast::ContractDefinition,
  8. ns: &mut Contract,
  9. errors: &mut Vec<Output>,
  10. ) -> bool {
  11. let mut broken = false;
  12. let mut vartab = Vartable::new();
  13. let mut cfg = ControlFlowGraph::new();
  14. for parts in &def.parts {
  15. if let ast::ContractPart::ContractVariableDefinition(ref s) = parts {
  16. if !var_decl(s, ns, &mut cfg, &mut vartab, errors) {
  17. broken = true;
  18. }
  19. }
  20. }
  21. cfg.add(&mut vartab, Instr::Return { value: Vec::new() });
  22. cfg.vars = vartab.drain();
  23. ns.initializer = cfg;
  24. broken
  25. }
  26. fn var_decl(
  27. s: &ast::ContractVariableDefinition,
  28. ns: &mut Contract,
  29. cfg: &mut ControlFlowGraph,
  30. vartab: &mut Vartable,
  31. errors: &mut Vec<Output>,
  32. ) -> bool {
  33. let ty = match ns.resolve_type(&s.ty, errors) {
  34. Ok(s) => s,
  35. Err(()) => {
  36. return false;
  37. }
  38. };
  39. let mut is_constant = false;
  40. let mut visibility: Option<ast::Visibility> = None;
  41. for attr in &s.attrs {
  42. match &attr {
  43. ast::VariableAttribute::Constant(loc) => {
  44. if is_constant {
  45. errors.push(Output::warning(
  46. loc.clone(),
  47. format!("duplicate constant attribute"),
  48. ));
  49. }
  50. is_constant = true;
  51. }
  52. ast::VariableAttribute::Visibility(ast::Visibility::External(loc)) => {
  53. errors.push(Output::error(
  54. loc.clone(),
  55. format!("variable cannot be declared external"),
  56. ));
  57. return false;
  58. }
  59. ast::VariableAttribute::Visibility(v) => {
  60. if let Some(e) = &visibility {
  61. errors.push(Output::error_with_note(
  62. v.loc().clone(),
  63. format!("variable visibility redeclared `{}'", v.to_string()),
  64. e.loc().clone(),
  65. format!("location of previous declaration of `{}'", e.to_string()),
  66. ));
  67. return false;
  68. }
  69. visibility = Some(v.clone());
  70. }
  71. }
  72. }
  73. let visibility = match visibility {
  74. Some(v) => v,
  75. None => ast::Visibility::Private(ast::Loc(0, 0)),
  76. };
  77. let var = if !is_constant {
  78. let storage = ns.top_of_contract_storage;
  79. ns.top_of_contract_storage += 1;
  80. ContractVariableType::Storage(storage)
  81. } else {
  82. ContractVariableType::Constant(ns.constants.len())
  83. };
  84. let initializer = if let Some(initializer) = &s.initializer {
  85. let expr = if is_constant {
  86. expression(&initializer, cfg, &ns, &mut None, errors)
  87. } else {
  88. expression(&initializer, cfg, &ns, &mut Some(vartab), errors)
  89. };
  90. let (res, resty) = match expr {
  91. Ok((res, ty)) => (res, ty),
  92. Err(()) => return false,
  93. };
  94. // implicityly conversion to correct ty
  95. let res = match cast(&s.loc, res, &resty, &ty, true, &ns, errors) {
  96. Ok(res) => res,
  97. Err(_) => return false,
  98. };
  99. Some(res)
  100. } else {
  101. if is_constant {
  102. errors.push(Output::decl_error(
  103. s.loc.clone(),
  104. format!("missing initializer for constant"),
  105. ));
  106. return false;
  107. }
  108. None
  109. };
  110. let sdecl = ContractVariable {
  111. name: s.name.name.to_string(),
  112. doc: s.doc.clone(),
  113. visibility,
  114. ty,
  115. var,
  116. };
  117. let pos = ns.variables.len();
  118. ns.variables.push(sdecl);
  119. if !ns.add_symbol(&s.name, Symbol::Variable(s.loc, pos), errors) {
  120. return false;
  121. }
  122. if let Some(res) = initializer {
  123. if is_constant {
  124. ns.constants.push(res);
  125. } else {
  126. let var = vartab.find(&s.name, ns, errors).unwrap();
  127. cfg.add(
  128. vartab,
  129. Instr::Set {
  130. res: var.pos,
  131. expr: res,
  132. },
  133. );
  134. set_contract_storage(&s.name, &var, cfg, vartab, errors).unwrap();
  135. }
  136. }
  137. true
  138. }