ref, add tests
This commit is contained in:
7
src/err.rs
Normal file
7
src/err.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use err_derive::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ParseError {
|
||||
#[error(display = "error syntax: {:?}", _0)]
|
||||
ErrorSyntax(String),
|
||||
}
|
||||
104
src/ins.rs
Normal file
104
src/ins.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InsType {
|
||||
Path(InsColl),
|
||||
Node(Instruction),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Ins {
|
||||
pub c: char,
|
||||
pub ins_type: InsType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InsColl {
|
||||
pub inses: Vec<Ins>,
|
||||
}
|
||||
|
||||
pub fn make_instruction_tree() -> InsColl {
|
||||
InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::Push) },
|
||||
Ins{ c: '马', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::Dup) },
|
||||
Ins{ c: '泥', ins_type: InsType::Node(Instruction::Swap) },
|
||||
Ins{ c: '马', ins_type: InsType::Node(Instruction::Pop) }
|
||||
]})},
|
||||
Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::CopyN) },
|
||||
Ins{ c: '马', ins_type: InsType::Node(Instruction::PopN) }
|
||||
]})},
|
||||
]})},
|
||||
Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::Add) },
|
||||
Ins{ c: '泥', ins_type: InsType::Node(Instruction::Sub) },
|
||||
Ins{ c: '马', ins_type: InsType::Node(Instruction::Mul) },
|
||||
]})},
|
||||
Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::Div) },
|
||||
Ins{ c: '泥', ins_type: InsType::Node(Instruction::Mod) },
|
||||
]})},
|
||||
]})},
|
||||
Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::Store) },
|
||||
Ins{ c: '泥', ins_type: InsType::Node(Instruction::Retrieve) },
|
||||
]})},
|
||||
Ins{ c: '马', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::StdOutChar) },
|
||||
Ins{ c: '泥', ins_type: InsType::Node(Instruction::StdOutNum) },
|
||||
]})},
|
||||
Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::StdInChar) },
|
||||
Ins{ c: '泥', ins_type: InsType::Node(Instruction::StdInNum) },
|
||||
]})},
|
||||
]})},
|
||||
]})},
|
||||
Ins{ c: '马', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::DefineLabel) },
|
||||
Ins{ c: '泥', ins_type: InsType::Node(Instruction::CallAtLabel) },
|
||||
Ins{ c: '马', ins_type: InsType::Node(Instruction::GotoLabel) },
|
||||
]})},
|
||||
Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '草', ins_type: InsType::Node(Instruction::GotoLabelE0) },
|
||||
Ins{ c: '泥', ins_type: InsType::Node(Instruction::GotoLabelL0) },
|
||||
Ins{ c: '马', ins_type: InsType::Node(Instruction::ReturnCallAt) },
|
||||
]})},
|
||||
Ins{ c: '马', ins_type: InsType::Path(InsColl{ inses: vec![
|
||||
Ins{ c: '马', ins_type: InsType::Node(Instruction::End) },
|
||||
]})},
|
||||
]})},
|
||||
]}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Instruction {
|
||||
Push,
|
||||
Dup,
|
||||
CopyN,
|
||||
Swap,
|
||||
Pop,
|
||||
PopN,
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
Store,
|
||||
Retrieve,
|
||||
DefineLabel,
|
||||
CallAtLabel,
|
||||
GotoLabel,
|
||||
GotoLabelE0,
|
||||
GotoLabelL0,
|
||||
ReturnCallAt,
|
||||
End,
|
||||
StdOutChar,
|
||||
StdOutNum,
|
||||
StdInChar,
|
||||
StdInNum,
|
||||
}
|
||||
166
src/main.rs
166
src/main.rs
@@ -1,112 +1,82 @@
|
||||
use err_derive::Error;
|
||||
pub mod err;// TODO ...
|
||||
mod ins;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ParseError {
|
||||
#[error(display = "error syntax: {:?}", _0)]
|
||||
ErrorSyntax(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Instruction {
|
||||
Push,
|
||||
Dup,
|
||||
CopyN,
|
||||
Swap,
|
||||
Pop,
|
||||
PopN,
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
Store,
|
||||
Retrieve,
|
||||
DefineLabel,
|
||||
CallAtLabel,
|
||||
GotoLabel,
|
||||
GotoLabelE0,
|
||||
GotoLabelL0,
|
||||
ReturnCallAt,
|
||||
End,
|
||||
StdOutChar,
|
||||
StdOutNum,
|
||||
StdInChar,
|
||||
StdInNum,
|
||||
}
|
||||
|
||||
struct ParseChars {
|
||||
index: usize,
|
||||
chars: Vec<char>,
|
||||
}
|
||||
|
||||
impl ParseChars {
|
||||
fn next(&mut self) -> Option<char> {
|
||||
let c = self.try_next();
|
||||
if c.is_some() { self.index += 1; }
|
||||
c
|
||||
}
|
||||
|
||||
fn try_next(&self) -> Option<char> {
|
||||
self.try_next_n(0_usize)
|
||||
}
|
||||
|
||||
fn try_next_n(&self, nn: usize) -> Option<char> {
|
||||
let i = self.index + nn;
|
||||
if i >= self.chars.len() {
|
||||
None
|
||||
} else {
|
||||
let c = self.chars[i];
|
||||
Some(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
use ins::*;
|
||||
|
||||
const VALID_INSTRUCTION_CHARS: &str = "草泥马河蟹";
|
||||
|
||||
// https://playsecurity.org/rawfile/grass_mud_horse_language_specification.md
|
||||
// https://p.rogram.me/grassmudhorse.js/grassmudhorse.js
|
||||
fn main() {
|
||||
let input = "草草草泥马 马草草草泥草草草草泥泥马 草马草 泥马草泥 草草草泥草泥草马 泥马草草 草草草泥马 泥草草草 草马草 草草草泥草泥泥马 泥草草泥 马泥草草泥草草草泥草泥马 马草马草泥草草草草泥泥马 马草草草泥草草草泥草泥马 草马马 马马马";
|
||||
|
||||
|
||||
let mut cs = "草草草泥草泥泥马".chars();
|
||||
println!("{}", read_number(&mut cs));
|
||||
println!("{:?}", parse_lang(input));
|
||||
}
|
||||
|
||||
fn parse_lang(lang: &str) -> Result<Vec<Instruction>, ParseError> {
|
||||
let mut r = vec![];
|
||||
|
||||
let mut cs = ParseChars{ index: 0_usize, chars: lang.chars().filter(|c| {
|
||||
VALID_INSTRUCTION_CHARS.chars().any(|vic| vic == *c)
|
||||
}).collect(), };
|
||||
while let Some(c) = cs.next() {
|
||||
let nc = match cs.try_next() {
|
||||
Some(nc) => nc, None => {
|
||||
return Err(ParseError::ErrorSyntax(
|
||||
format!("Syntax error: after {} has no valid char", c)
|
||||
));
|
||||
},
|
||||
};
|
||||
if c == '草' && nc == '草' { // Push
|
||||
cs.next();
|
||||
// todo parse
|
||||
continue;
|
||||
fn read_number(cs: &mut dyn Iterator<Item=char>) -> isize {
|
||||
let mut is_positive = 1_isize;
|
||||
if let Some(c) = cs.next() {
|
||||
if c == '草' {
|
||||
is_positive = 1;
|
||||
} else if c == '泥' {
|
||||
is_positive = -1;
|
||||
} else {
|
||||
// Syntax ERROR!
|
||||
}
|
||||
let nnc = match cs.try_next_n(1) {
|
||||
Some(nc) => nc, None => {
|
||||
return Err(ParseError::ErrorSyntax(
|
||||
format!("Syntax error: after {}{} has no valid char", c, nc)
|
||||
));
|
||||
},
|
||||
};
|
||||
if c == '草' && nc == '马' || nnc == '草' { // Dup
|
||||
|
||||
}
|
||||
let nnnc = match cs.try_next_n(2) {
|
||||
Some(nc) => nc, None => {
|
||||
return Err(ParseError::ErrorSyntax(
|
||||
format!("Syntax error: after {}{}{} has no valid char", c, nc, nnc)
|
||||
));
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// Syntax ERROR!
|
||||
}
|
||||
|
||||
Ok(r)
|
||||
let mut num = 0_isize;
|
||||
while let Some(c) = cs.next() {
|
||||
if c == '马' {
|
||||
break;
|
||||
} else {
|
||||
num <<= 1;
|
||||
num += if c == '草' { 0 } else { 1 };
|
||||
}
|
||||
}
|
||||
is_positive * num
|
||||
}
|
||||
|
||||
fn match_instruction(ins_coll: &InsColl, cs: &mut dyn Iterator<Item=char>) -> Option<Instruction> {
|
||||
if let Some(c) = cs.next() {
|
||||
for ins in &ins_coll.inses {
|
||||
if ins.c == c {
|
||||
match &ins.ins_type {
|
||||
InsType::Path(ins_coll) => return match_instruction(&ins_coll, cs),
|
||||
InsType::Node(ins) => {
|
||||
println!("{:?}", ins);
|
||||
return Some(ins.clone());
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("ERROR!!!! syntax error!");
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn parse_lang(lang: &str) {// -> Result<Vec<Instruction>, ParseError> {
|
||||
// let mut r = vec![];
|
||||
|
||||
let instruction_tree_root = make_instruction_tree();
|
||||
|
||||
let mut cs = lang.chars().filter(|c| {
|
||||
VALID_INSTRUCTION_CHARS.chars().any(|vic| vic == *c)
|
||||
});
|
||||
|
||||
while let Some(ins) = match_instruction(&instruction_tree_root, &mut cs) {
|
||||
println!("{:?}", ins);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_number() {
|
||||
assert_eq!(read_number(&mut "草泥马".chars()), 1);
|
||||
assert_eq!(read_number(&mut "草泥草草草草泥泥马".chars()), 67);
|
||||
assert_eq!(read_number(&mut "草泥草泥泥马".chars()), 11);
|
||||
assert_eq!(read_number(&mut "草泥草草草泥草泥马".chars()), 69);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user