Skip to content

Instantly share code, notes, and snippets.

@Lucifier129
Created March 12, 2022 11:53
Show Gist options
  • Save Lucifier129/ca0605e72ca2faa28bc3ec7f59a205f2 to your computer and use it in GitHub Desktop.
Save Lucifier129/ca0605e72ca2faa28bc3ec7f59a205f2 to your computer and use it in GitHub Desktop.
use std::collections::HashMap;
extern crate peg;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Variable(String);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum Value {
Integer(i32),
Variable(Variable),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum Statement {
Println(Value),
Subtraction(Variable, Value),
Addition(Variable, Value),
Assignment(Variable, Value),
IfZero(Value, Statements),
}
type Statements = Vec<Statement>;
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub struct Program {
statements: Statements,
}
peg::parser! {
grammar parser() for str {
rule _ = [' ' | '\n' | '\t']*
rule digit() -> &'input str
= n:$(['0'..='9']) { n }
rule letter() -> &'input str
= n:$(['a'..='z' | 'A'..='Z']) { n }
rule alpha_numeric() -> &'input str
= n:$(letter() / digit()) { n }
rule integer() -> i32
= n:$(['0'..='9']+) { n.parse().unwrap() }
rule variable() -> Variable
= n:$(letter() alpha_numeric()*) {
Variable(n.to_string())
}
rule integer_value() -> Value
= n:integer() { Value::Integer(n) }
rule variable_value() -> Value
= n:variable() { Value::Variable(n) }
rule value() -> Value
= n:(integer_value() / variable_value()) { n }
rule println() -> Statement
= "!" _ v:value() { Statement::Println(v) }
rule addition() -> Statement
= v:variable() _ "+=" _ n:value() { Statement::Addition(v, n) }
rule subtraction() -> Statement
= v:variable() _ "-=" _ n:value() { Statement::Subtraction(v, n) }
rule assignment() -> Statement
= v:variable() _ "=" _ n:value() { Statement::Assignment(v, n) }
rule if_zero() -> Statement
= "?" _ v:value() _ "{" vs:statements() "}" { Statement::IfZero(v, vs) }
rule statement() -> Statement
= _ n:(println() / assignment() / subtraction() / addition() / if_zero()) _
{ n }
rule statement_separator() -> ()
= _ ";" _ {}
rule statements() -> Statements
= vs:(statement() ** statement_separator()) statement_separator()? { vs }
pub rule program() -> Program
= vs:statements() { Program { statements: vs } }
}
}
fn eval_statements(statements: Statements, variables: &mut HashMap<Variable, i32>) {
for statement in statements {
match statement {
Statement::Println(value) => match value {
Value::Integer(i) => println!("{}", i),
Value::Variable(v) => println!("{}", variables.get(&v).unwrap()),
},
Statement::Subtraction(variable, value) => {
let variable_value = variables.get(&variable).unwrap();
let value = match value {
Value::Integer(i) => i,
Value::Variable(v) => variables.get(&v).copied().unwrap(),
};
let new_value = *variable_value - value;
variables.insert(variable, new_value);
}
Statement::Addition(variable, value) => {
let variable_value = variables.get(&variable).unwrap();
let value = match value {
Value::Integer(i) => i,
Value::Variable(v) => variables.get(&v).copied().unwrap(),
};
let new_value = *variable_value + value;
variables.insert(variable, new_value);
}
Statement::Assignment(variable, value) => {
let value = match value {
Value::Integer(i) => i,
Value::Variable(v) => variables.get(&v).copied().unwrap(),
};
variables.insert(variable, value);
}
Statement::IfZero(value, statements) => {
let value = match value {
Value::Integer(i) => i,
Value::Variable(v) => variables.get(&v).copied().unwrap(),
};
if value == 0 {
eval_statements(statements, variables);
}
}
}
}
}
fn eval(program: &Program) {
let mut variables = HashMap::new();
eval_statements(program.statements.clone(), &mut variables);
}
fn main() {
let source = r#"
a = 0;
b = 1;
c = 1;
b += a;
c += b;
? a {
! b;
b = 0;
};
? b {
! c;
c = 0;
};
? c {
! a;
}
"#;
let program = parser::program(source).unwrap();
println!("source\n{}\n", source);
println!("ast\n{:?}\n", program);
println!("result");
eval(&program);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment