statement.rs 9.3 KB

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