type1.rs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. use crate::{
  2. opcode::{self, ext_opcode, opcode},
  3. parser::{
  4. choice,
  5. comment_scope,
  6. extract,
  7. id,
  8. take,
  9. take_to_end_of_pkglength,
  10. take_u32,
  11. try_with_context,
  12. ParseResult,
  13. Parser,
  14. Propagate,
  15. },
  16. pkg_length::{pkg_length, PkgLength},
  17. term_object::{term_arg, term_list},
  18. AmlContext,
  19. AmlError,
  20. DebugVerbosity,
  21. };
  22. /// Type 1 opcodes do not return a value and so can't be used in expressions.
  23. pub fn type1_opcode<'a, 'c>() -> impl Parser<'a, 'c, ()>
  24. where
  25. 'c: 'a,
  26. {
  27. /*
  28. * Type1Opcode := DefBreak | DefBreakPoint | DefContinue | DefFatal | DefIfElse | DefLoad | DefNoop |
  29. * DefNotify | DefRelease | DefReset | DefReturn | DefSignal | DefSleep | DefStall |
  30. * DefWhile
  31. */
  32. comment_scope(
  33. DebugVerbosity::AllScopes,
  34. "Type1Opcode",
  35. choice!(def_break(), def_breakpoint(), def_fatal(), def_if_else(), def_noop(), def_return(), def_while()),
  36. )
  37. }
  38. fn def_break<'a, 'c>() -> impl Parser<'a, 'c, ()>
  39. where
  40. 'c: 'a,
  41. {
  42. /*
  43. * DefBreak := 0xa5
  44. */
  45. opcode(opcode::DEF_BREAK_OP)
  46. .then(comment_scope(
  47. DebugVerbosity::AllScopes,
  48. "DefBreak",
  49. id().map(|()| -> Result<(), Propagate> { Err(Propagate::Break) }),
  50. ))
  51. .discard_result()
  52. }
  53. fn def_breakpoint<'a, 'c>() -> impl Parser<'a, 'c, ()>
  54. where
  55. 'c: 'a,
  56. {
  57. /*
  58. * DefBreakPoint := 0xcc
  59. * TODO: there is no debugger, so this doesn't do anything. If there was, this should stop execution and enter
  60. * the AML debugger.
  61. */
  62. opcode(opcode::DEF_BREAKPOINT_OP)
  63. .then(comment_scope(DebugVerbosity::AllScopes, "DefBreakPoint", id()))
  64. .discard_result()
  65. }
  66. fn def_fatal<'a, 'c>() -> impl Parser<'a, 'c, ()>
  67. where
  68. 'c: 'a,
  69. {
  70. /*
  71. * DefFatal := ExtOpPrefix 0x32 FatalType FatalCode FatalArg
  72. * FatalType := ByteData
  73. * FatalCode := DWordData
  74. * FatalArg := TermArg => Integer
  75. */
  76. ext_opcode(opcode::EXT_DEF_FATAL_OP)
  77. .then(comment_scope(
  78. DebugVerbosity::Scopes,
  79. "DefFatal",
  80. take().then(take_u32()).then(term_arg()).map_with_context(
  81. |((fatal_type, fatal_code), fatal_arg), context| -> (Result<(), Propagate>, &'c mut AmlContext) {
  82. let fatal_arg = try_with_context!(context, fatal_arg.as_integer(context));
  83. context.handler.handle_fatal_error(fatal_type, fatal_code, fatal_arg);
  84. (Err(Propagate::Err(AmlError::FatalError)), context)
  85. },
  86. ),
  87. ))
  88. .discard_result()
  89. }
  90. fn def_if_else<'a, 'c>() -> impl Parser<'a, 'c, ()>
  91. where
  92. 'c: 'a,
  93. {
  94. /*
  95. * DefIfElse := 0xa0 PkgLength Predicate TermList DefElse
  96. * Predicate := TermArg => Integer (0 = false, >0 = true)
  97. * DefElse := Nothing | <0xa1 PkgLength TermList>
  98. */
  99. opcode(opcode::DEF_IF_ELSE_OP)
  100. .then(comment_scope(
  101. DebugVerbosity::Scopes,
  102. "DefIfElse",
  103. pkg_length()
  104. .then(term_arg())
  105. .feed(|(length, predicate_arg)| {
  106. take_to_end_of_pkglength(length)
  107. .map(move |then_branch| Ok((predicate_arg.as_bool()?, then_branch)))
  108. })
  109. .then(choice!(
  110. opcode(opcode::DEF_ELSE_OP)
  111. .then(comment_scope(
  112. DebugVerbosity::AllScopes,
  113. "DefElse",
  114. pkg_length().feed(|length| take_to_end_of_pkglength(length))
  115. ))
  116. .map(|((), else_branch): ((), &[u8])| Ok(else_branch)),
  117. // TODO: can this be `id().map(&[])`?
  118. |input, context| -> ParseResult<'a, 'c, &[u8]> {
  119. /*
  120. * This path parses an DefIfElse that doesn't have an else branch. We simply
  121. * return an empty slice, so if the predicate is false, we don't execute
  122. * anything.
  123. */
  124. Ok((input, context, &[]))
  125. }
  126. ))
  127. .map_with_context(|((predicate, then_branch), else_branch), context| {
  128. let branch = if predicate { then_branch } else { else_branch };
  129. match term_list(PkgLength::from_raw_length(branch, branch.len() as u32).unwrap())
  130. .parse(branch, context)
  131. {
  132. Ok((_, context, result)) => (Ok(result), context),
  133. Err((_, context, err)) => (Err(err), context),
  134. }
  135. }),
  136. ))
  137. .discard_result()
  138. }
  139. fn def_noop<'a, 'c>() -> impl Parser<'a, 'c, ()>
  140. where
  141. 'c: 'a,
  142. {
  143. /*
  144. * DefNoop := 0xa3
  145. */
  146. opcode(opcode::DEF_NOOP_OP).then(comment_scope(DebugVerbosity::AllScopes, "DefNoop", id())).discard_result()
  147. }
  148. fn def_return<'a, 'c>() -> impl Parser<'a, 'c, ()>
  149. where
  150. 'c: 'a,
  151. {
  152. /*
  153. * DefReturn := 0xa4 ArgObject
  154. * ArgObject := TermArg => DataRefObject
  155. */
  156. opcode(opcode::DEF_RETURN_OP)
  157. .then(comment_scope(
  158. DebugVerbosity::Scopes,
  159. "DefReturn",
  160. term_arg().map(|return_arg| -> Result<(), Propagate> {
  161. /*
  162. * To return a value, we want to halt execution of the method and propagate the
  163. * return value all the way up to the start of the method invocation. To do this,
  164. * we emit a special error that is intercepted during method invocation and turned
  165. * into a valid result.
  166. */
  167. Err(Propagate::Return(return_arg))
  168. }),
  169. ))
  170. .discard_result()
  171. }
  172. fn def_while<'a, 'c>() -> impl Parser<'a, 'c, ()>
  173. where
  174. 'c: 'a,
  175. {
  176. /*
  177. * DefWhile := 0xa2 PkgLength Predicate TermList
  178. * Predicate := TermArg => Integer (0 = false, >0 = true)
  179. *
  180. * Parsing this does something a little unusual - it 'extracts' the predicate when it's first parsed, which
  181. * allows us to reevaluate it to see if we should break out of the while yet. This is required, to make sure
  182. * we're observing changes to the context between the iterations of the loop.
  183. */
  184. opcode(opcode::DEF_WHILE_OP)
  185. .then(comment_scope(
  186. DebugVerbosity::Scopes,
  187. "DefWhile",
  188. pkg_length()
  189. .then(extract(term_arg()))
  190. .feed(move |(length, (first_predicate, predicate_stream))| {
  191. take_to_end_of_pkglength(length)
  192. .map(move |body| Ok((first_predicate.clone(), predicate_stream, body)))
  193. })
  194. .map_with_context(|(first_predicate, predicate_stream, body), mut context| {
  195. if !try_with_context!(context, first_predicate.as_bool()) {
  196. return (Ok(()), context);
  197. }
  198. loop {
  199. match term_list(PkgLength::from_raw_length(body, body.len() as u32).unwrap())
  200. .parse(body, context)
  201. {
  202. Ok((_, new_context, result)) => {
  203. context = new_context;
  204. }
  205. // TODO: differentiate real errors and special Propagates (e.g. break, continue, etc.)
  206. Err((_, new_context, Propagate::Break)) => {
  207. context = new_context;
  208. break;
  209. }
  210. Err((_, context, err)) => return (Err(err), context),
  211. }
  212. // Reevaluate the predicate to see if we should break out of the loop yet
  213. let predicate =
  214. match comment_scope(DebugVerbosity::AllScopes, "WhilePredicate", term_arg())
  215. .parse(predicate_stream, context)
  216. {
  217. Ok((_, new_context, result)) => {
  218. context = new_context;
  219. try_with_context!(context, result.as_bool())
  220. }
  221. Err((_, context, err)) => return (Err(err), context),
  222. };
  223. if !predicate {
  224. break;
  225. }
  226. }
  227. (Ok(()), context)
  228. }),
  229. ))
  230. .discard_result()
  231. }