diff --git a/etk-asm/src/asm.rs b/etk-asm/src/asm.rs index 66a92af..47a6e66 100644 --- a/etk-asm/src/asm.rs +++ b/etk-asm/src/asm.rs @@ -582,6 +582,8 @@ impl Assembler { #[derive(Clone, Copy, Debug, PartialEq)] struct EOFCodeSection { size: u16, + inputs: u8, + outputs: u8, max_stack_height: u16, } @@ -591,9 +593,16 @@ impl Assembler { for section_bounds in self.sections.windows(2) { if let [start, end] = section_bounds { let size = (end.position - start.position) as u16; - if let EOFSectionKind::Code { max_stack_height } = start.kind { + if let EOFSectionKind::Code { + inputs, + outputs, + max_stack_height, + } = start.kind + { code_sections.push(EOFCodeSection { size, + inputs, + outputs, max_stack_height, }); } else { @@ -605,9 +614,16 @@ impl Assembler { // add last section if let Some(&last_section) = self.sections.last() { let size = (self.concrete_len - last_section.position) as u16; - if let EOFSectionKind::Code { max_stack_height } = last_section.kind { + if let EOFSectionKind::Code { + inputs, + outputs, + max_stack_height, + } = last_section.kind + { code_sections.push(EOFCodeSection { size, + inputs, + outputs, max_stack_height, }); } else { @@ -636,8 +652,8 @@ impl Assembler { output.push(0x00); // types section for code_section in code_sections { - // TODO all functions are 0 inputs, non-returning for now - output.extend_from_slice(&[0x00, 0x80]); + output.push(code_section.inputs); + output.push(code_section.outputs); output.extend_from_slice(&code_section.max_stack_height.to_be_bytes()); } Ok(()) @@ -1666,6 +1682,8 @@ mod tests { AbstractOp::new(Push0), AbstractOp::new(Stop), AbstractOp::EOFSection(EOFSectionKind::Code { + inputs: 0, + outputs: 0, max_stack_height: 0, }), AbstractOp::new(Stop), @@ -1682,6 +1700,8 @@ mod tests { let code = vec![ AbstractOp::EOFSection(EOFSectionKind::Code { + inputs: 0, + outputs: 0x80, max_stack_height: 1, }), AbstractOp::new(Push0), @@ -1689,6 +1709,8 @@ mod tests { AbstractOp::EOFSection(EOFSectionKind::Data), AbstractOp::new(JumpDest), AbstractOp::EOFSection(EOFSectionKind::Code { + inputs: 0, + outputs: 0, max_stack_height: 0, }), AbstractOp::new(Stop), diff --git a/etk-asm/src/ops.rs b/etk-asm/src/ops.rs index ad55138..3b8338b 100644 --- a/etk-asm/src/ops.rs +++ b/etk-asm/src/ops.rs @@ -170,6 +170,10 @@ impl Access { pub enum EOFSectionKind { /// Code section Code { + /// Code section's inputs + inputs: u8, + /// Code section's outputs or 0x80 if secton is non-returning + outputs: u8, /// Code section's max stack height max_stack_height: u16, }, diff --git a/etk-asm/src/parse/asm.pest b/etk-asm/src/parse/asm.pest index cccb771..3a4197f 100644 --- a/etk-asm/src/parse/asm.pest +++ b/etk-asm/src/parse/asm.pest @@ -73,8 +73,12 @@ function_parameter = @{ ASCII_ALPHA ~ ASCII_ALPHANUMERIC* } ////////////// section = ${ "section" ~ WHITESPACE ~ section_kind ~ (WHITESPACE ~ section_attributes)? } section_kind = { ".code" | ".data" } -section_attributes = { max_stack_height_attribute? } +section_attributes = { (section_attribute ~WHITESPACE?)* } +section_attribute = { inputs_attribute | outputs_attribute | max_stack_height_attribute } max_stack_height_attribute = { "max_stack_height" ~ "=" ~ number } +inputs_attribute = { "inputs" ~ "=" ~ number } +outputs_attribute = { "outputs" ~ "=" ~ (number | nonreturning) } +nonreturning = { "nonret" } ////////////// // operands // diff --git a/etk-asm/src/parse/mod.rs b/etk-asm/src/parse/mod.rs index 514c80c..5180dc0 100644 --- a/etk-asm/src/parse/mod.rs +++ b/etk-asm/src/parse/mod.rs @@ -3,6 +3,7 @@ mod expression; mod macros; pub(crate) mod error; + mod parser { #![allow(clippy::upper_case_acronyms)] @@ -54,34 +55,7 @@ fn parse_abstract_op(pair: Pair) -> Result { let op = Op::new(spec).unwrap(); AbstractOp::Op(op) } - Rule::section => { - let mut pairs = pair.into_inner(); - let section_kind = pairs.next().unwrap().as_str(); - - if section_kind == ".code" { - let max_stack_height = { - if let Some(section_attributes) = pairs.next() { - if let Some(msh_pair) = section_attributes.into_inner().next() { - msh_pair - .into_inner() - .next() - .unwrap() - .as_str() - .parse::() - .unwrap() - } else { - 0 - } - } else { - 0 - } - }; - AbstractOp::EOFSection(EOFSectionKind::Code { max_stack_height }) - } else { - // attributes are ignored - AbstractOp::EOFSection(EOFSectionKind::Data) - } - } + Rule::section => parse_section(pair)?, _ => unreachable!(), }; @@ -107,6 +81,48 @@ fn parse_push(pair: Pair) -> Result { Ok(AbstractOp::Op(spec.with(expr).unwrap())) } +fn parse_section(pair: Pair) -> Result { + let mut pairs = pair.into_inner(); + let section_kind = pairs.next().unwrap().as_str(); + + if section_kind == ".code" { + let mut inputs: u8 = 0; + let mut outputs: u8 = 0x80; // non-returning by default + let mut max_stack_height: u16 = 0; + if let Some(section_attributes) = pairs.next() { + for attribute in section_attributes.into_inner() { + let attr_inner = attribute.into_inner().next().unwrap(); + + match attr_inner.as_rule() { + Rule::max_stack_height_attribute => { + let max_stack_height_str = attr_inner.into_inner().next().unwrap().as_str(); + max_stack_height = max_stack_height_str.parse::().unwrap(); + } + Rule::inputs_attribute => { + let inputs_str = attr_inner.into_inner().next().unwrap().as_str(); + inputs = inputs_str.parse::().unwrap(); + } + Rule::outputs_attribute => { + let outputs_str = attr_inner.into_inner().next().unwrap().as_str(); + if outputs_str != "nonret" { + outputs = outputs_str.parse::().unwrap(); + } + } + _ => unreachable!(), + } + } + } + Ok(AbstractOp::EOFSection(EOFSectionKind::Code { + inputs, + outputs, + max_stack_height, + })) + } else { + // attributes are ignored + Ok(AbstractOp::EOFSection(EOFSectionKind::Data)) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/etk-asm/tests/asm.rs b/etk-asm/tests/asm.rs index 4f6f5a8..1c87566 100644 --- a/etk-asm/tests/asm.rs +++ b/etk-asm/tests/asm.rs @@ -369,10 +369,7 @@ fn test_eof_multiple_code_sections() -> Result<(), Error> { let mut ingester = Ingest::new(&mut output); ingester.ingest_file(source(&["eof", "main2.etk"]))?; - assert_eq!( - output, - hex!("ef0001 01000c 020003000100010003 040000 00 00800000 00800000 00800002 00 fe 5f5ff3") - ); + assert_eq!(output, hex!("ef0001 010010 0200040001000100030004 040000 00 00800000 00800000 00800002 01000002 00 fe 5f5ff3 505f5f00")); Ok(()) } diff --git a/etk-asm/tests/asm/eof/main2.etk b/etk-asm/tests/asm/eof/main2.etk index ebd0feb..48a5e4c 100644 --- a/etk-asm/tests/asm/eof/main2.etk +++ b/etk-asm/tests/asm/eof/main2.etk @@ -1,10 +1,16 @@ section .code stop -section .code +section .code outputs=nonret invalid -section .code max_stack_height=2 +section .code outputs=nonret max_stack_height=2 +push0 +push0 +return + +section .code inputs=1 outputs=0 max_stack_height=2 +pop push0 push0 -return \ No newline at end of file +stop \ No newline at end of file