Skip to content

Commit

Permalink
🚧 oracle文実装中
Browse files Browse the repository at this point in the history
  • Loading branch information
liebe-magi committed Aug 19, 2024
1 parent ec48b0d commit 1b0db54
Show file tree
Hide file tree
Showing 8 changed files with 526 additions and 93 deletions.
48 changes: 48 additions & 0 deletions examples/oracle.aby
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// シンプルな書き方
forge x: arcana = -5;
oracle {
(x > 0) => unveil("x is positive");
(x < 0) => unveil("x is negative");
_ => unveil("x is zero");
};

// 条件文にOmen型を使う場合
oracle (x > 0) {
(boon) => unveil("x is positive");
(hex) => unveil("x is negative or zero");
};

// 条件文にOmen型以外を使う場合
oracle (y = x ^ 2) {
(y > 100) => unveil("y is greater than 100");
(y == 100) => unveil("y is equal to 100");
_ => unveil("y is less than 100");
};

oracle (a = "abyss-lang") {
(a == "abyss") => unveil("a is abyss");
_ => unveil("a is not abyss");
};

// 条件文に複数の条件を使う場合
oracle (a = 3, b = 2) {
(a == 1 && b == 2) => unveil("a is 1 and b is 2");
(a != 1 && b == 2) => unveil("a is not 1 and b is 2");
(a == 1 && b != 2) => unveil("a is 1 and b is not 2");
_ => unveil("a is not 1 and b is not 2");
};

// xが正の場合、xを表示する、xが負の場合、xを反転して表示する
forge x: arcana = -5;
forge y: arcana = oracle (x > 0) {
(boon) => reveal(x);
(hex) => {
forge z: arcana = x * (-1);
oracle {
(z > 0) => unveil("z is positive");
(z < 0) => unveil("z is negative");
_ => unveil("z is zero");
};
reveal(z);
};
};
34 changes: 23 additions & 11 deletions src/abyss.pest
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,22 @@ line_comment = _{ "//" ~ (!"\n" ~ ANY)* }
block_comment = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" }

statements = { SOI ~ statement* ~ EOI }
statement = { (forge_var | assignment | unveil | expression) ~ ";" }
statement = { (forge_var | assignment | unveil | reveal | expression) ~ ";" }
block = { "{" ~ statement* ~ "}" ~ ";" }

forge_var = { "forge" ~ morph? ~ identifier ~ ":" ~ type ~ "=" ~ expression }
assignment = { identifier ~ assignment_op ~ expression }
unveil = { "unveil" ~ "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
reveal = { "reveal" ~ "(" ~ expression ~ ")" }

oracle_expr = { "oracle" ~ oracle_conditional? ~ "{" ~ oracle_branch* ~ "}" }
oracle_conditional = { "(" ~ (conditional_assignments | expressions) ~ ")" }
conditional_assignments = { conditional_assignment ~ ("," ~ conditional_assignment)* }
conditional_assignment = { identifier ~ "=" ~ expression }

oracle_branch = { pattern ~ "=>" ~ (block | statement) }
pattern = { "(" ~ expressions ~ ")" | default_pattern }
default_pattern = { "_" }

identifier = @{ ASCII_ALPHANUMERIC+ }
type = { "omen" | "aether" | "arcana" | "rune" }
Expand All @@ -21,16 +32,17 @@ rune = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" }
sign = { "+" | "-" }
morph = { "morph" }

expression = { trans_expr | or_expr }
trans_expr = { "trans" ~ "(" ~ expression ~ "as" ~ type ~ ")" }
or_expr = { and_expr ~ (or_op ~ and_expr)* }
and_expr = { not_expr ~ (and_op ~ not_expr)* }
not_expr = { not_op? ~ comp_expr }
comp_expr = { add_expr ~ (comp_op ~ add_expr)? }
add_expr = { mul_expr ~ (add_op ~ mul_expr)* }
mul_expr = { pow_expr ~ (mul_op ~ pow_expr)* }
pow_expr = { factor ~ (pow_op ~ factor)* }
factor = { omen | aether | arcana | rune | identifier | "(" ~ expression ~ ")" }
expressions = { expression ~ ("," ~ expression)* }
expression = { trans_expr | oracle_expr | or_expr }
trans_expr = { "trans" ~ "(" ~ expression ~ "as" ~ type ~ ")" }
or_expr = { and_expr ~ (or_op ~ and_expr)* }
and_expr = { not_expr ~ (and_op ~ not_expr)* }
not_expr = { not_op? ~ comp_expr }
comp_expr = { add_expr ~ (comp_op ~ add_expr)? }
add_expr = { mul_expr ~ (add_op ~ mul_expr)* }
mul_expr = { pow_expr ~ (mul_op ~ pow_expr)* }
pow_expr = { factor ~ (pow_op ~ factor)* }
factor = { omen | aether | arcana | rune | identifier | "(" ~ expression ~ ")" }

assignment_op = { "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "**=" | "=" }

Expand Down
28 changes: 22 additions & 6 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,32 @@ pub enum AST {
op: AssignmentOp,
line_info: Option<LineInfo>,
},
Var {
name: String,
var_type: Type,
is_morph: bool,
line_info: Option<LineInfo>,
},
Var(String, Option<LineInfo>),
Unveil(Vec<AST>, Option<LineInfo>),
Trans(Box<AST>, Type, Option<LineInfo>),
Reveal(Box<AST>, Option<LineInfo>),
Oracle {
is_match: bool,
conditionals: Vec<ConditionalAssignment>,
branches: Vec<OracleBranch>,
line_info: Option<LineInfo>,
},
OracleDefaultBranch(Option<LineInfo>), // Block(Vec<AST>, Option<LineInfo>),
}

#[derive(Debug, Clone)]
pub struct ConditionalAssignment {
pub variable: String, // 条件文で参照する変数
pub expression: Box<AST>, // 変数に代入される式
pub line_info: Option<LineInfo>,
}

#[derive(Debug, Clone)]
pub struct OracleBranch {
pub pattern: Vec<AST>,
pub body: Box<AST>,
pub line_info: Option<LineInfo>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
Arcana,
Expand Down
87 changes: 53 additions & 34 deletions src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,53 @@ use crate::ast::{LineInfo, Type};
use crate::eval::EvalError;
use std::collections::HashMap;

#[derive(Debug)]
pub struct VarInfo {
pub value: Value,
pub var_type: Type,
pub is_morph: bool,
}

#[derive(Debug)]
pub struct Environment {
vars: HashMap<String, VarInfo>,
scopes: Vec<HashMap<String, VarInfo>>,
}

impl Environment {
pub fn new() -> Self {
Environment {
vars: HashMap::new(),
scopes: vec![HashMap::new()],
}
}

pub fn push_scope(&mut self) {
self.scopes.push(HashMap::new());
}

pub fn pop_scope(&mut self) {
self.scopes.pop();
}

pub fn set_var(&mut self, name: String, value: Value, var_type: Type, is_morph: bool) {
self.vars.insert(
name,
VarInfo {
value,
var_type,
is_morph,
},
);
if let Some(current_scope) = self.scopes.last_mut() {
current_scope.insert(
name,
VarInfo {
value,
var_type,
is_morph,
},
);
}
}

pub fn get_var(&self, name: &str) -> Option<&VarInfo> {
self.vars.get(name)
for scope in self.scopes.iter().rev() {
if let Some(var_info) = scope.get(name) {
return Some(var_info);
}
}
None
}

pub fn update_var(
Expand All @@ -41,35 +58,37 @@ impl Environment {
var_type: Type,
line_info: Option<LineInfo>, // LineInfoを追加
) -> Result<(), EvalError> {
if let Some(var_info) = self.vars.get_mut(name) {
// 変数が可変でない場合、エラーを返す
if !var_info.is_morph {
return Err(EvalError::InvalidOperation(
format!("Cannot reassign to immutable variable {}", name),
line_info,
));
}
for scope in self.scopes.iter_mut().rev() {
if let Some(var_info) = scope.get_mut(name) {
// 変数が可変でない場合、エラーを返す
if !var_info.is_morph {
return Err(EvalError::InvalidOperation(
format!("Cannot reassign to immutable variable {}", name),
line_info,
));
}

// 変数の型が異なる場合、エラーを返す
if var_info.var_type != var_type {
return Err(EvalError::InvalidOperation(
format!(
"Type mismatch: cannot assign {:?} to variable {} of type {:?}",
var_type, name, var_info.var_type
),
line_info,
));
}
// 変数の型が異なる場合、エラーを返す
if var_info.var_type != var_type {
return Err(EvalError::InvalidOperation(
format!(
"Type mismatch: cannot assign {:?} to variable {} of type {:?}",
var_type, name, var_info.var_type
),
line_info,
));
}

// 書き換えが許可され、型も一致している場合、値を更新
var_info.value = value;
Ok(())
} else {
Err(EvalError::UndefinedVariable(name.to_string(), line_info))
// 書き換えが許可され、型も一致している場合、値を更新
var_info.value = value;
return Ok(());
}
}
Err(EvalError::UndefinedVariable(name.to_string(), line_info))
}
}

#[derive(Debug)]
pub enum Value {
Omen(bool),
Arcana(i64),
Expand Down
Loading

0 comments on commit 1b0db54

Please sign in to comment.