stl + brainfuck sample program
This commit is contained in:
@@ -32,20 +32,25 @@
|
|||||||
<to><integer value="3" /></to>
|
<to><integer value="3" /></to>
|
||||||
<step><integer value="1" /></step>
|
<step><integer value="1" /></step>
|
||||||
<do>
|
<do>
|
||||||
<insert-array>
|
<call function="array-push">
|
||||||
<array><value variable="a" /></array>
|
<arguments>
|
||||||
<value><value variable="i" /></value>
|
<value variable="a" />
|
||||||
</insert-array>
|
<value variable="i" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
</do>
|
</do>
|
||||||
</for>
|
</for>
|
||||||
<print>
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
<call function="sum">
|
<call function="sum">
|
||||||
<arguments>
|
<arguments>
|
||||||
<value variable="a" />
|
<value variable="a" />
|
||||||
</arguments>
|
</arguments>
|
||||||
</call>
|
</call>
|
||||||
</print>
|
</arguments>
|
||||||
<print>
|
</call>
|
||||||
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
<call function="sum">
|
<call function="sum">
|
||||||
<arguments>
|
<arguments>
|
||||||
<array>
|
<array>
|
||||||
@@ -55,6 +60,7 @@
|
|||||||
</array>
|
</array>
|
||||||
</arguments>
|
</arguments>
|
||||||
</call>
|
</call>
|
||||||
</print>
|
</arguments>
|
||||||
|
</call>
|
||||||
</main>
|
</main>
|
||||||
</program>
|
</program>
|
||||||
369
sample/bf.pl.xml
Normal file
369
sample/bf.pl.xml
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
<program name="brainfuck">
|
||||||
|
<main>
|
||||||
|
<assign variable="prog">
|
||||||
|
<call function="string-split">
|
||||||
|
<arguments>
|
||||||
|
<call function="input">
|
||||||
|
<arguments />
|
||||||
|
</call>
|
||||||
|
<string value="" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</assign>
|
||||||
|
<assign variable="i">
|
||||||
|
<integer value="0" />
|
||||||
|
</assign>
|
||||||
|
<assign variable="p">
|
||||||
|
<integer value="0" />
|
||||||
|
</assign>
|
||||||
|
<assign variable="t">
|
||||||
|
<array />
|
||||||
|
</assign>
|
||||||
|
<for variable="_">
|
||||||
|
<from><integer value="0" /></from>
|
||||||
|
<to><integer value="100" /></to>
|
||||||
|
<step><integer value="1" /></step>
|
||||||
|
<do>
|
||||||
|
<call function="array-push">
|
||||||
|
<arguments>
|
||||||
|
<value variable="t" />
|
||||||
|
<integer value="0" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</do>
|
||||||
|
</for>
|
||||||
|
<while>
|
||||||
|
<not>
|
||||||
|
<equal>
|
||||||
|
<value variable="i" />
|
||||||
|
<call function="array-length">
|
||||||
|
<arguments>
|
||||||
|
<value variable="prog" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</equal>
|
||||||
|
</not>
|
||||||
|
<do>
|
||||||
|
<assign variable="c">
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="prog" />
|
||||||
|
<value variable="i" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</assign>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<string value="+" />
|
||||||
|
<value variable="c" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<call function="array-set">
|
||||||
|
<arguments>
|
||||||
|
<value variable="t" />
|
||||||
|
<value variable="p" />
|
||||||
|
<add>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="t" />
|
||||||
|
<value variable="p" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<integer value="1" />
|
||||||
|
</add>
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<string value="-" />
|
||||||
|
<value variable="c" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<call function="array-set">
|
||||||
|
<arguments>
|
||||||
|
<value variable="t" />
|
||||||
|
<value variable="p" />
|
||||||
|
<subtract>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="t" />
|
||||||
|
<value variable="p" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<integer value="1" />
|
||||||
|
</subtract>
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<string value=">" />
|
||||||
|
<value variable="c" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<assign variable="p">
|
||||||
|
<add>
|
||||||
|
<value variable="p" />
|
||||||
|
<integer value="1" />
|
||||||
|
</add>
|
||||||
|
</assign>
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<string value="<" />
|
||||||
|
<value variable="c" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<assign variable="p">
|
||||||
|
<subtract>
|
||||||
|
<value variable="p" />
|
||||||
|
<integer value="1" />
|
||||||
|
</subtract>
|
||||||
|
</assign>
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<string value="." />
|
||||||
|
<value variable="c" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="t" />
|
||||||
|
<value variable="p" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<string value="," />
|
||||||
|
<value variable="c" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<string value="[" />
|
||||||
|
<value variable="c" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<if>
|
||||||
|
<not>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="t" />
|
||||||
|
<value variable="p" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</not>
|
||||||
|
<then>
|
||||||
|
<assign variable="open">
|
||||||
|
<integer value="0" />
|
||||||
|
</assign>
|
||||||
|
<assign variable="i">
|
||||||
|
<add>
|
||||||
|
<value variable="i" />
|
||||||
|
<integer value="1" />
|
||||||
|
</add>
|
||||||
|
</assign>
|
||||||
|
<while>
|
||||||
|
<not>
|
||||||
|
<and>
|
||||||
|
<equal>
|
||||||
|
<value variable="open" />
|
||||||
|
<integer value="0" />
|
||||||
|
</equal>
|
||||||
|
<equal>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="prog" />
|
||||||
|
<value variable="i" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<string value="]" />
|
||||||
|
</equal>
|
||||||
|
</and>
|
||||||
|
</not>
|
||||||
|
<do>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="prog" />
|
||||||
|
<value variable="i" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<string value="[" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<assign variable="open">
|
||||||
|
<add>
|
||||||
|
<value variable="open" />
|
||||||
|
<integer value="1" />
|
||||||
|
</add>
|
||||||
|
</assign>
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="prog" />
|
||||||
|
<value variable="i" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<string value="]" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<assign variable="open">
|
||||||
|
<subtract>
|
||||||
|
<value variable="open" />
|
||||||
|
<integer value="1" />
|
||||||
|
</subtract>
|
||||||
|
</assign>
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
|
<assign variable="i">
|
||||||
|
<add>
|
||||||
|
<value variable="i" />
|
||||||
|
<integer value="1" />
|
||||||
|
</add>
|
||||||
|
</assign>
|
||||||
|
</do>
|
||||||
|
</while>
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<string value="]" />
|
||||||
|
<value variable="c" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<if>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="t" />
|
||||||
|
<value variable="p" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<then>
|
||||||
|
<assign variable="open">
|
||||||
|
<integer value="0" />
|
||||||
|
</assign>
|
||||||
|
<assign variable="i">
|
||||||
|
<subtract>
|
||||||
|
<value variable="i" />
|
||||||
|
<integer value="1" />
|
||||||
|
</subtract>
|
||||||
|
</assign>
|
||||||
|
<while>
|
||||||
|
<not>
|
||||||
|
<and>
|
||||||
|
<equal>
|
||||||
|
<value variable="open" />
|
||||||
|
<integer value="0" />
|
||||||
|
</equal>
|
||||||
|
<equal>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="prog" />
|
||||||
|
<value variable="i" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<string value="[" />
|
||||||
|
</equal>
|
||||||
|
</and>
|
||||||
|
</not>
|
||||||
|
<do>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="prog" />
|
||||||
|
<value variable="i" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<string value="[" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<assign variable="open">
|
||||||
|
<subtract>
|
||||||
|
<value variable="open" />
|
||||||
|
<integer value="1" />
|
||||||
|
</subtract>
|
||||||
|
</assign>
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
|
<if>
|
||||||
|
<equal>
|
||||||
|
<call function="array-get">
|
||||||
|
<arguments>
|
||||||
|
<value variable="prog" />
|
||||||
|
<value variable="i" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<string value="]" />
|
||||||
|
</equal>
|
||||||
|
<then>
|
||||||
|
<assign variable="open">
|
||||||
|
<add>
|
||||||
|
<value variable="open" />
|
||||||
|
<integer value="1" />
|
||||||
|
</add>
|
||||||
|
</assign>
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
|
<assign variable="i">
|
||||||
|
<subtract>
|
||||||
|
<value variable="i" />
|
||||||
|
<integer value="1" />
|
||||||
|
</subtract>
|
||||||
|
</assign>
|
||||||
|
</do>
|
||||||
|
</while>
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
<assign variable="i">
|
||||||
|
<add>
|
||||||
|
<value variable="i" />
|
||||||
|
<integer value="1" />
|
||||||
|
</add>
|
||||||
|
</assign>
|
||||||
|
</do>
|
||||||
|
</while>
|
||||||
|
</main>
|
||||||
|
</program>
|
||||||
@@ -3,14 +3,18 @@
|
|||||||
<if>
|
<if>
|
||||||
<integer value="1" />
|
<integer value="1" />
|
||||||
<then>
|
<then>
|
||||||
<print>
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
<string value="TRUE" />
|
<string value="TRUE" />
|
||||||
</print>
|
</arguments>
|
||||||
|
</call>
|
||||||
</then>
|
</then>
|
||||||
<else>
|
<else>
|
||||||
<print>
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
<string value="FALSE" />
|
<string value="FALSE" />
|
||||||
</print>
|
</arguments>
|
||||||
|
</call>
|
||||||
</else>
|
</else>
|
||||||
</if>
|
</if>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
40
sample/stl.pl.xml
Normal file
40
sample/stl.pl.xml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<program>
|
||||||
|
<main>
|
||||||
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
|
<integer value="1" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<assign variable="arr">
|
||||||
|
<array>
|
||||||
|
<float value="0.1" />
|
||||||
|
</array>
|
||||||
|
</assign>
|
||||||
|
<call function="array-set">
|
||||||
|
<arguments>
|
||||||
|
<value variable="arr" />
|
||||||
|
<integer value="0" />
|
||||||
|
<float value="0.5" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
<each variable="v">
|
||||||
|
<value variable="arr" />
|
||||||
|
<do>
|
||||||
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
|
<value variable="v" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</do>
|
||||||
|
</each>
|
||||||
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
|
<call function="array-pop">
|
||||||
|
<arguments>
|
||||||
|
<value variable="arr" />
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</arguments>
|
||||||
|
</call>
|
||||||
|
</main>
|
||||||
|
</program>
|
||||||
@@ -24,8 +24,10 @@
|
|||||||
</arguments>
|
</arguments>
|
||||||
</call>
|
</call>
|
||||||
</assign>
|
</assign>
|
||||||
<print>
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
<value variable="b" />
|
<value variable="b" />
|
||||||
</print>
|
</arguments>
|
||||||
|
</call>
|
||||||
</main>
|
</main>
|
||||||
</program>
|
</program>
|
||||||
@@ -6,9 +6,11 @@
|
|||||||
<while>
|
<while>
|
||||||
<value variable="a" />
|
<value variable="a" />
|
||||||
<do>
|
<do>
|
||||||
<print>
|
<call function="print">
|
||||||
|
<arguments>
|
||||||
<value variable="a" />
|
<value variable="a" />
|
||||||
</print>
|
</arguments>
|
||||||
|
</call>
|
||||||
<assign variable="a">
|
<assign variable="a">
|
||||||
<subtract>
|
<subtract>
|
||||||
<value variable="a" />
|
<value variable="a" />
|
||||||
|
|||||||
351
src/lib.rs
351
src/lib.rs
@@ -37,6 +37,9 @@ pub enum Instruction {
|
|||||||
And(Vec<Instruction>),
|
And(Vec<Instruction>),
|
||||||
Or(Vec<Instruction>),
|
Or(Vec<Instruction>),
|
||||||
Not(Box<Instruction>),
|
Not(Box<Instruction>),
|
||||||
|
Equal(Box<Instruction>, Box<Instruction>),
|
||||||
|
Greater(Box<Instruction>, Box<Instruction>),
|
||||||
|
Lower(Box<Instruction>, Box<Instruction>),
|
||||||
Call(Box<Instruction>, Vec<Instruction>),
|
Call(Box<Instruction>, Vec<Instruction>),
|
||||||
CallNamed(String, Vec<Instruction>),
|
CallNamed(String, Vec<Instruction>),
|
||||||
Return(Box<Instruction>),
|
Return(Box<Instruction>),
|
||||||
@@ -51,14 +54,10 @@ pub enum Instruction {
|
|||||||
},
|
},
|
||||||
Each(String, Box<Instruction>, Vec<Instruction>),
|
Each(String, Box<Instruction>, Vec<Instruction>),
|
||||||
While(Box<Instruction>, Vec<Instruction>),
|
While(Box<Instruction>, Vec<Instruction>),
|
||||||
Print(Box<Instruction>),
|
|
||||||
AssignArray(Box<Instruction>, Box<Instruction>, Box<Instruction>),
|
|
||||||
InsertArray(Box<Instruction>, Box<Instruction>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
pub fn new(node: Node) -> Result<Instruction, Box<dyn Error>> {
|
pub fn new(node: Node) -> Result<Instruction, Box<dyn Error>> {
|
||||||
// println!("parsing '{}'", util::tag_name(&node));
|
|
||||||
Ok(match util::tag_name(&node).as_str() {
|
Ok(match util::tag_name(&node).as_str() {
|
||||||
"value" => Instruction::Value(
|
"value" => Instruction::Value(
|
||||||
node.attribute("variable")
|
node.attribute("variable")
|
||||||
@@ -100,6 +99,39 @@ impl Instruction {
|
|||||||
node.first_element_child()
|
node.first_element_child()
|
||||||
.ok_or("missing value child element in 'not' tag")?,
|
.ok_or("missing value child element in 'not' tag")?,
|
||||||
)?)),
|
)?)),
|
||||||
|
"equal" => {
|
||||||
|
let children: Vec<Node> = node.children().filter(Node::is_element).collect();
|
||||||
|
if children.len() == 2 {
|
||||||
|
Instruction::Equal(
|
||||||
|
Box::new(Instruction::new(children[0])?),
|
||||||
|
Box::new(Instruction::new(children[1])?),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err("bad child count in 'equal' tag")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"greater" => {
|
||||||
|
let children: Vec<Node> = node.children().filter(Node::is_element).collect();
|
||||||
|
if children.len() == 2 {
|
||||||
|
Instruction::Greater(
|
||||||
|
Box::new(Instruction::new(children[0])?),
|
||||||
|
Box::new(Instruction::new(children[1])?),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err("bad child count in 'greater' tag")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"lower" => {
|
||||||
|
let children: Vec<Node> = node.children().filter(Node::is_element).collect();
|
||||||
|
if children.len() == 2 {
|
||||||
|
Instruction::Lower(
|
||||||
|
Box::new(Instruction::new(children[0])?),
|
||||||
|
Box::new(Instruction::new(children[1])?),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err("bad child count in 'lower' tag")?
|
||||||
|
}
|
||||||
|
}
|
||||||
"call" => {
|
"call" => {
|
||||||
if let Some(function) = node.attribute("function") {
|
if let Some(function) = node.attribute("function") {
|
||||||
Instruction::CallNamed(
|
Instruction::CallNamed(
|
||||||
@@ -180,39 +212,6 @@ impl Instruction {
|
|||||||
)?),
|
)?),
|
||||||
Instruction::from_children(util::find_node(&node, "do")?)?,
|
Instruction::from_children(util::find_node(&node, "do")?)?,
|
||||||
),
|
),
|
||||||
"print" => Instruction::Print(Box::new(Instruction::new(
|
|
||||||
node.first_element_child()
|
|
||||||
.ok_or("missing value child element in 'print' tag")?,
|
|
||||||
)?)),
|
|
||||||
"assign-array" => Instruction::AssignArray(
|
|
||||||
Box::new(Instruction::new(
|
|
||||||
util::find_node(&node, "array")?
|
|
||||||
.first_element_child()
|
|
||||||
.ok_or("missing 'array' in 'assign-array' tag")?,
|
|
||||||
)?),
|
|
||||||
Box::new(Instruction::new(
|
|
||||||
util::find_node(&node, "index")?
|
|
||||||
.first_element_child()
|
|
||||||
.ok_or("missing 'index' in 'assign-array' tag")?,
|
|
||||||
)?),
|
|
||||||
Box::new(Instruction::new(
|
|
||||||
util::find_node(&node, "value")?
|
|
||||||
.first_element_child()
|
|
||||||
.ok_or("missing 'value' in 'assign-array' tag")?,
|
|
||||||
)?),
|
|
||||||
),
|
|
||||||
"insert-array" => Instruction::InsertArray(
|
|
||||||
Box::new(Instruction::new(
|
|
||||||
util::find_node(&node, "array")?
|
|
||||||
.first_element_child()
|
|
||||||
.ok_or("missing 'array' in 'insert-array' tag")?,
|
|
||||||
)?),
|
|
||||||
Box::new(Instruction::new(
|
|
||||||
util::find_node(&node, "value")?
|
|
||||||
.first_element_child()
|
|
||||||
.ok_or("missing 'value' in 'insert-array' tag")?,
|
|
||||||
)?),
|
|
||||||
),
|
|
||||||
tag => Err(format!("unknown tag '{}'", tag))?,
|
tag => Err(format!("unknown tag '{}'", tag))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -406,6 +405,61 @@ impl Instruction {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compare(v1: Value, v2: Value) -> Result<i64, Box<dyn Error>> {
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
match v1 {
|
||||||
|
Value::Integer(i1) => match v2 {
|
||||||
|
Value::Integer(i2) => Ok(i1 - i2),
|
||||||
|
Value::Float(f2) => Ok(
|
||||||
|
match (i1 as f64)
|
||||||
|
.partial_cmp(&f2)
|
||||||
|
.ok_or("incompatible comparison values")?
|
||||||
|
{
|
||||||
|
Ordering::Less => -1,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
Ordering::Greater => 1,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_ => Err("incompatible comparison values")?,
|
||||||
|
},
|
||||||
|
Value::Float(f1) => match v2 {
|
||||||
|
Value::Integer(i2) => Ok(
|
||||||
|
match f1
|
||||||
|
.partial_cmp(&(i2 as f64))
|
||||||
|
.ok_or("incompatible comparison values")?
|
||||||
|
{
|
||||||
|
Ordering::Less => -1,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
Ordering::Greater => 1,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Value::Float(f2) => Ok(
|
||||||
|
match f1
|
||||||
|
.partial_cmp(&f2)
|
||||||
|
.ok_or("incompatible comparison values")?
|
||||||
|
{
|
||||||
|
Ordering::Less => -1,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
Ordering::Greater => 1,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_ => Err("incompatible comparison values")?,
|
||||||
|
},
|
||||||
|
Value::String(s1) => {
|
||||||
|
if let Value::String(s2) = v2 {
|
||||||
|
Ok(match s1.cmp(&s2) {
|
||||||
|
Ordering::Less => -1,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
Ordering::Greater => 1,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err("incompatible comparison values")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err("incompatible comparison values")?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run_all(
|
fn run_all(
|
||||||
ins: &Vec<Instruction>,
|
ins: &Vec<Instruction>,
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
@@ -469,6 +523,39 @@ impl Instruction {
|
|||||||
.run(ctx)?
|
.run(ctx)?
|
||||||
.ok_or("invalid child value in 'not' tag")?
|
.ok_or("invalid child value in 'not' tag")?
|
||||||
.to_bool()
|
.to_bool()
|
||||||
|
{
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::Equal(v1, v2) => Some(Value::Integer(
|
||||||
|
if Instruction::compare(
|
||||||
|
v1.run(ctx)?.ok_or("invalid child value in 'equal' tag")?,
|
||||||
|
v2.run(ctx)?.ok_or("invalid child value in 'equal' tag")?,
|
||||||
|
)? == 0
|
||||||
|
{
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::Greater(v1, v2) => Some(Value::Integer(
|
||||||
|
if Instruction::compare(
|
||||||
|
v1.run(ctx)?.ok_or("invalid child value in 'equal' tag")?,
|
||||||
|
v2.run(ctx)?.ok_or("invalid child value in 'equal' tag")?,
|
||||||
|
)? > 0
|
||||||
|
{
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::Lower(v1, v2) => Some(Value::Integer(
|
||||||
|
if Instruction::compare(
|
||||||
|
v1.run(ctx)?.ok_or("invalid child value in 'equal' tag")?,
|
||||||
|
v2.run(ctx)?.ok_or("invalid child value in 'equal' tag")?,
|
||||||
|
)? < 0
|
||||||
{
|
{
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
@@ -483,6 +570,8 @@ impl Instruction {
|
|||||||
.ok_or("invalid child function in 'call' tag")?;
|
.ok_or("invalid child function in 'call' tag")?;
|
||||||
if let Value::Function(f) = fct_val {
|
if let Value::Function(f) = fct_val {
|
||||||
f.run(vals, ctx)?
|
f.run(vals, ctx)?
|
||||||
|
} else if let Value::StdFunction(f) = fct_val {
|
||||||
|
f(vals)?
|
||||||
} else {
|
} else {
|
||||||
Err("invalid function")?
|
Err("invalid function")?
|
||||||
}
|
}
|
||||||
@@ -494,6 +583,8 @@ impl Instruction {
|
|||||||
if let Value::Function(f) = fct_val {
|
if let Value::Function(f) = fct_val {
|
||||||
let mut local = ctx.clone();
|
let mut local = ctx.clone();
|
||||||
f.run(vals, &mut local)?
|
f.run(vals, &mut local)?
|
||||||
|
} else if let Value::StdFunction(f) = fct_val {
|
||||||
|
f(vals)?
|
||||||
} else {
|
} else {
|
||||||
Err("invalid function")?
|
Err("invalid function")?
|
||||||
}
|
}
|
||||||
@@ -586,38 +677,6 @@ impl Instruction {
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Instruction::Print(ins) => {
|
|
||||||
match ins.run(ctx)?.ok_or("invalid child value in 'print' tag")? {
|
|
||||||
Value::Integer(i) => println!("{}", i),
|
|
||||||
Value::Float(f) => println!("{}", f),
|
|
||||||
Value::String(s) => println!("{}", s),
|
|
||||||
_ => Err("Unprintable value")?,
|
|
||||||
};
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Instruction::AssignArray(array_ins, index_ins, value_ins) => {
|
|
||||||
if let Some(Value::Array(vec)) = array_ins.run(ctx)? {
|
|
||||||
if let Some(Value::Integer(index)) = index_ins.run(ctx)? {
|
|
||||||
vec.borrow_mut().insert(
|
|
||||||
index.try_into()?,
|
|
||||||
value_ins
|
|
||||||
.run(ctx)?
|
|
||||||
.ok_or("invalid 'value' value in 'assign-array' tag")?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Instruction::InsertArray(array_ins, value_ins) => {
|
|
||||||
if let Some(Value::Array(vec)) = array_ins.run(ctx)? {
|
|
||||||
vec.borrow_mut().push(
|
|
||||||
value_ins
|
|
||||||
.run(ctx)?
|
|
||||||
.ok_or("invalid 'value' value in 'insert-array' tag")?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -658,6 +717,7 @@ pub enum Value {
|
|||||||
String(String),
|
String(String),
|
||||||
Array(Rc<RefCell<Vec<Value>>>),
|
Array(Rc<RefCell<Vec<Value>>>),
|
||||||
Function(Function),
|
Function(Function),
|
||||||
|
StdFunction(fn(Vec<Value>) -> Result<Option<Value>, Box<dyn Error>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
@@ -701,12 +761,165 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod stl {
|
||||||
|
use super::*;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub fn inject_all(ctx: &mut Context) {
|
||||||
|
ctx.assign(String::from("print"), Value::StdFunction(print));
|
||||||
|
ctx.assign(String::from("input"), Value::StdFunction(input));
|
||||||
|
ctx.assign(
|
||||||
|
String::from("string-split"),
|
||||||
|
Value::StdFunction(string_split),
|
||||||
|
);
|
||||||
|
ctx.assign(String::from("array-set"), Value::StdFunction(array_set));
|
||||||
|
ctx.assign(String::from("array-push"), Value::StdFunction(array_push));
|
||||||
|
ctx.assign(String::from("array-pop"), Value::StdFunction(array_pop));
|
||||||
|
ctx.assign(String::from("array-get"), Value::StdFunction(array_get));
|
||||||
|
ctx.assign(String::from("array-length"), Value::StdFunction(array_length));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
|
||||||
|
if vals.len() == 1 {
|
||||||
|
match &vals[0] {
|
||||||
|
Value::Integer(i) => println!("{}", i),
|
||||||
|
Value::Float(f) => println!("{}", f),
|
||||||
|
Value::String(s) => println!("{}", s),
|
||||||
|
v => println!("{:?}", v)
|
||||||
|
// _ => Err("unprintable value")?,
|
||||||
|
};
|
||||||
|
Ok(Some(vals[0].clone()))
|
||||||
|
} else {
|
||||||
|
Err("bad argument count in call to 'print'")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
|
||||||
|
if vals.len() == 0 {
|
||||||
|
let mut line = String::new();
|
||||||
|
io::stdin().read_line(&mut line)?;
|
||||||
|
line.pop();
|
||||||
|
Ok(Some(Value::String(line)))
|
||||||
|
} else {
|
||||||
|
Err("bad argument count in call to 'input'")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_split(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
|
||||||
|
if vals.len() == 2 {
|
||||||
|
if let Value::String(s) = &vals[0] {
|
||||||
|
if let Value::String(d) = &vals[1] {
|
||||||
|
let mut v = s.split(d)
|
||||||
|
.map(|sub| Value::String(sub.to_string()))
|
||||||
|
.collect::<Vec<Value>>();
|
||||||
|
v.remove(0);
|
||||||
|
v.pop();
|
||||||
|
Ok(Some(Value::Array(Rc::new(RefCell::new(v)))))
|
||||||
|
} else {
|
||||||
|
Err("invalid delimiter string in call to 'string-split'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("invalid target string in call to 'string-split'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("bad argument count in call to 'string-split'")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_set(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
|
||||||
|
if vals.len() == 3 {
|
||||||
|
if let Value::Array(v) = &vals[0] {
|
||||||
|
if let Value::Integer(i) = &vals[1] {
|
||||||
|
let index: usize = (*i).try_into()?;
|
||||||
|
if v.borrow().len() > index {
|
||||||
|
v.borrow_mut()[index] = vals[2].clone();
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err("index out of array in call to 'array-set'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("invalid index in call to 'array-set'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("invalid array in call to 'array-set'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("bad argument count in call to 'array-set'")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_push(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
|
||||||
|
if vals.len() == 2 {
|
||||||
|
if let Value::Array(v) = &vals[0] {
|
||||||
|
v.borrow_mut().push(vals[1].clone());
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err("invalid array in call to 'array-push'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("bad argument count in call to 'array-push'")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_pop(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
|
||||||
|
if vals.len() == 1 {
|
||||||
|
if let Value::Array(v) = &vals[0] {
|
||||||
|
Ok(Some(
|
||||||
|
v.borrow_mut()
|
||||||
|
.pop()
|
||||||
|
.ok_or("empty array in call to 'array-pop'")?,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err("invalid array in call to 'array-pop'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("bad argument count in call to 'array-pop'")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_get(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
|
||||||
|
if vals.len() == 2 {
|
||||||
|
if let Value::Array(v) = &vals[0] {
|
||||||
|
if let Value::Integer(i) = &vals[1] {
|
||||||
|
let index: usize = (*i).try_into()?;
|
||||||
|
if v.borrow().len() > index {
|
||||||
|
Ok(Some(v.borrow_mut()[index].clone()))
|
||||||
|
} else {
|
||||||
|
Err("index out of array in call to 'array-get'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("invalid index in call to 'array-get'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("invalid array in call to 'array-get'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("bad argument count in call to 'array-get'")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_length(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
|
||||||
|
if vals.len() == 1 {
|
||||||
|
if let Value::Array(v) = &vals[0] {
|
||||||
|
Ok(Some(
|
||||||
|
Value::Integer(v.borrow().len() as i64)
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err("invalid array in call to 'array-length'")?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("bad argument count in call to 'array-length'")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(filename: &str) -> Result<(), Box<dyn Error>> {
|
pub fn run(filename: &str) -> Result<(), Box<dyn Error>> {
|
||||||
let contents = fs::read_to_string(filename)?;
|
let contents = fs::read_to_string(filename)?;
|
||||||
let doc = Document::parse(&contents)?;
|
let doc = Document::parse(&contents)?;
|
||||||
let root = doc.root();
|
let root = doc.root();
|
||||||
|
|
||||||
let mut ctx = Context::new(None);
|
let mut ctx = Context::new(None);
|
||||||
|
stl::inject_all(&mut ctx);
|
||||||
|
|
||||||
let main = root
|
let main = root
|
||||||
.first_element_child()
|
.first_element_child()
|
||||||
|
|||||||
Reference in New Issue
Block a user