Finish implementing term parsing
This commit is contained in:
parent
3530364ea8
commit
5b98e8a29c
@ -4,7 +4,7 @@ mod terms;
|
|||||||
|
|
||||||
pub(crate) use helpers::word_boundary;
|
pub(crate) use helpers::word_boundary;
|
||||||
pub use names::{function_or_predicate_name, variable_name};
|
pub use names::{function_or_predicate_name, variable_name};
|
||||||
pub use terms::{boolean, function, integer, predicate, special_integer, string, variable,
|
pub use terms::{boolean, function, integer, predicate, special_integer, string, term, variable,
|
||||||
variable_declaration};
|
variable_declaration};
|
||||||
|
|
||||||
pub struct Declarations
|
pub struct Declarations
|
||||||
|
@ -5,7 +5,7 @@ use nom::
|
|||||||
bytes::complete::{escaped_transform, tag},
|
bytes::complete::{escaped_transform, tag},
|
||||||
character::complete::{digit1, multispace0, none_of},
|
character::complete::{digit1, multispace0, none_of},
|
||||||
combinator::{map, map_res, opt, recognize},
|
combinator::{map, map_res, opt, recognize},
|
||||||
multi::separated_list,
|
multi::{many1, separated_list},
|
||||||
sequence::{delimited, pair, preceded, terminated},
|
sequence::{delimited, pair, preceded, terminated},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,6 +37,23 @@ fn false_(i: &str) -> IResult<&str, crate::Term>
|
|||||||
)(i)
|
)(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn negative<'i>(i: &'i str, d: &Declarations) -> IResult<&'i str, crate::Term>
|
||||||
|
{
|
||||||
|
map
|
||||||
|
(
|
||||||
|
preceded
|
||||||
|
(
|
||||||
|
terminated
|
||||||
|
(
|
||||||
|
tag("-"),
|
||||||
|
multispace0,
|
||||||
|
),
|
||||||
|
|i| term_precedence_0(i, d),
|
||||||
|
),
|
||||||
|
|x| crate::Term::negative(Box::new(x)),
|
||||||
|
)(i)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn boolean(i: &str) -> IResult<&str, crate::Term>
|
pub fn boolean(i: &str) -> IResult<&str, crate::Term>
|
||||||
{
|
{
|
||||||
alt
|
alt
|
||||||
@ -149,7 +166,7 @@ pub fn string(i: &str) -> IResult<&str, crate::Term>
|
|||||||
)(i)
|
)(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_or_predicate<'i>(i: &'i str, declarations: &Declarations)
|
fn function_or_predicate<'i>(i: &'i str, d: &Declarations)
|
||||||
-> IResult<&'i str, (&'i str, Option<Vec<Box<crate::Term>>>)>
|
-> IResult<&'i str, (&'i str, Option<Vec<Box<crate::Term>>>)>
|
||||||
{
|
{
|
||||||
pair
|
pair
|
||||||
@ -173,10 +190,9 @@ fn function_or_predicate<'i>(i: &'i str, declarations: &Declarations)
|
|||||||
tag(","),
|
tag(","),
|
||||||
multispace0,
|
multispace0,
|
||||||
),
|
),
|
||||||
// TODO: fix
|
|
||||||
map
|
map
|
||||||
(
|
(
|
||||||
integer,
|
|i| term(i, d),
|
||||||
Box::new,
|
Box::new,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -190,11 +206,11 @@ fn function_or_predicate<'i>(i: &'i str, declarations: &Declarations)
|
|||||||
)(i)
|
)(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn function<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str, crate::Function>
|
pub fn function<'i>(i: &'i str, d: &Declarations) -> IResult<&'i str, crate::Function>
|
||||||
{
|
{
|
||||||
map
|
map
|
||||||
(
|
(
|
||||||
|i| function_or_predicate(i, declarations),
|
|i| function_or_predicate(i, d),
|
||||||
|(name, arguments)|
|
|(name, arguments)|
|
||||||
{
|
{
|
||||||
let arguments = match arguments
|
let arguments = match arguments
|
||||||
@ -203,7 +219,7 @@ pub fn function<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str,
|
|||||||
None => vec![],
|
None => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut function_declarations = declarations.function_declarations.borrow_mut();
|
let mut function_declarations = d.function_declarations.borrow_mut();
|
||||||
|
|
||||||
let declaration = match function_declarations.iter()
|
let declaration = match function_declarations.iter()
|
||||||
.find(|x| x.name == name && x.arity == arguments.len())
|
.find(|x| x.name == name && x.arity == arguments.len())
|
||||||
@ -229,11 +245,11 @@ pub fn function<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str,
|
|||||||
)(i)
|
)(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn predicate<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str, crate::Predicate>
|
pub fn predicate<'i>(i: &'i str, d: &Declarations) -> IResult<&'i str, crate::Predicate>
|
||||||
{
|
{
|
||||||
map
|
map
|
||||||
(
|
(
|
||||||
|i| function_or_predicate(i, declarations),
|
|i| function_or_predicate(i, d),
|
||||||
|(name, arguments)|
|
|(name, arguments)|
|
||||||
{
|
{
|
||||||
let arguments = match arguments
|
let arguments = match arguments
|
||||||
@ -242,7 +258,7 @@ pub fn predicate<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str
|
|||||||
None => vec![],
|
None => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut predicate_declarations = declarations.predicate_declarations.borrow_mut();
|
let mut predicate_declarations = d.predicate_declarations.borrow_mut();
|
||||||
|
|
||||||
let declaration = match predicate_declarations.iter()
|
let declaration = match predicate_declarations.iter()
|
||||||
.find(|x| x.name == name && x.arity == arguments.len())
|
.find(|x| x.name == name && x.arity == arguments.len())
|
||||||
@ -277,15 +293,14 @@ pub fn variable_declaration(i: &str) -> IResult<&str, crate::VariableDeclaration
|
|||||||
)(i)
|
)(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variable<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str, crate::Variable>
|
pub fn variable<'i>(i: &'i str, d: &Declarations) -> IResult<&'i str, crate::Variable>
|
||||||
{
|
{
|
||||||
map
|
map
|
||||||
(
|
(
|
||||||
variable_name,
|
variable_name,
|
||||||
|name|
|
|name|
|
||||||
{
|
{
|
||||||
let mut variable_declaration_stack =
|
let mut variable_declaration_stack = d.variable_declaration_stack.borrow_mut();
|
||||||
declarations.variable_declaration_stack.borrow_mut();
|
|
||||||
|
|
||||||
let declaration = variable_declaration_stack.find_or_create(name);
|
let declaration = variable_declaration_stack.find_or_create(name);
|
||||||
|
|
||||||
@ -294,11 +309,310 @@ pub fn variable<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str,
|
|||||||
)(i)
|
)(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn term_parenthesized<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term>
|
||||||
|
{
|
||||||
|
delimited
|
||||||
|
(
|
||||||
|
terminated
|
||||||
|
(
|
||||||
|
tag("("),
|
||||||
|
multispace0,
|
||||||
|
),
|
||||||
|
|i| term(i, d),
|
||||||
|
preceded
|
||||||
|
(
|
||||||
|
multispace0,
|
||||||
|
tag(")"),
|
||||||
|
),
|
||||||
|
)(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term_precedence_0<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term>
|
||||||
|
{
|
||||||
|
alt
|
||||||
|
((
|
||||||
|
special_integer,
|
||||||
|
integer,
|
||||||
|
map
|
||||||
|
(
|
||||||
|
|i| function(i, d),
|
||||||
|
crate::Term::Function,
|
||||||
|
),
|
||||||
|
string,
|
||||||
|
map
|
||||||
|
(
|
||||||
|
|i| variable(i, d),
|
||||||
|
crate::Term::Variable,
|
||||||
|
),
|
||||||
|
|i| term_parenthesized(i, d),
|
||||||
|
))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term_precedence_1<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term>
|
||||||
|
{
|
||||||
|
alt
|
||||||
|
((
|
||||||
|
|i| negative(i, d),
|
||||||
|
|i| term_precedence_0(i, d),
|
||||||
|
))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term_precedence_2<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term>
|
||||||
|
{
|
||||||
|
alt
|
||||||
|
((
|
||||||
|
map
|
||||||
|
(
|
||||||
|
pair
|
||||||
|
(
|
||||||
|
many1
|
||||||
|
(
|
||||||
|
terminated
|
||||||
|
(
|
||||||
|
|i| term_precedence_1(i, d),
|
||||||
|
delimited
|
||||||
|
(
|
||||||
|
multispace0,
|
||||||
|
tag("**"),
|
||||||
|
multispace0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|i| term_precedence_1(i, d),
|
||||||
|
),
|
||||||
|
|(arguments, last_argument)| arguments.into_iter().rev().fold(last_argument,
|
||||||
|
|accumulator, argument|
|
||||||
|
crate::Term::exponentiate(Box::new(argument), Box::new(accumulator))),
|
||||||
|
),
|
||||||
|
|i| term_precedence_1(i, d),
|
||||||
|
))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term_precedence_3<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term>
|
||||||
|
{
|
||||||
|
alt
|
||||||
|
((
|
||||||
|
map
|
||||||
|
(
|
||||||
|
pair
|
||||||
|
(
|
||||||
|
|i| term_precedence_2(i, d),
|
||||||
|
many1
|
||||||
|
(
|
||||||
|
pair
|
||||||
|
(
|
||||||
|
delimited
|
||||||
|
(
|
||||||
|
multispace0,
|
||||||
|
alt
|
||||||
|
((
|
||||||
|
tag("*"),
|
||||||
|
tag("/"),
|
||||||
|
tag("%"),
|
||||||
|
)),
|
||||||
|
multispace0,
|
||||||
|
),
|
||||||
|
|i| term_precedence_2(i, d),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|(first_argument, arguments)| arguments.into_iter().fold(first_argument,
|
||||||
|
|accumulator, (operator, argument)|
|
||||||
|
match operator
|
||||||
|
{
|
||||||
|
"*" => crate::Term::multiply(Box::new(accumulator), Box::new(argument)),
|
||||||
|
"/" => crate::Term::divide(Box::new(accumulator), Box::new(argument)),
|
||||||
|
"%" => crate::Term::modulo(Box::new(accumulator), Box::new(argument)),
|
||||||
|
// TODO: handle appropriately
|
||||||
|
_ => panic!("test"),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|i| term_precedence_2(i, d),
|
||||||
|
))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term_precedence_4<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term>
|
||||||
|
{
|
||||||
|
alt
|
||||||
|
((
|
||||||
|
map
|
||||||
|
(
|
||||||
|
pair
|
||||||
|
(
|
||||||
|
|i| term_precedence_3(i, d),
|
||||||
|
many1
|
||||||
|
(
|
||||||
|
pair
|
||||||
|
(
|
||||||
|
delimited
|
||||||
|
(
|
||||||
|
multispace0,
|
||||||
|
alt
|
||||||
|
((
|
||||||
|
tag("+"),
|
||||||
|
tag("-"),
|
||||||
|
)),
|
||||||
|
multispace0,
|
||||||
|
),
|
||||||
|
|i| term_precedence_3(i, d),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|(first_argument, arguments)| arguments.into_iter().fold(first_argument,
|
||||||
|
|accumulator, (operator, argument)|
|
||||||
|
match operator
|
||||||
|
{
|
||||||
|
"+" => crate::Term::add(Box::new(accumulator), Box::new(argument)),
|
||||||
|
"-" => crate::Term::subtract(Box::new(accumulator), Box::new(argument)),
|
||||||
|
// TODO: handle appropriately
|
||||||
|
_ => panic!("test"),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|i| term_precedence_3(i, d),
|
||||||
|
))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term_precedence_5<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term>
|
||||||
|
{
|
||||||
|
alt
|
||||||
|
((
|
||||||
|
map
|
||||||
|
(
|
||||||
|
delimited
|
||||||
|
(
|
||||||
|
terminated
|
||||||
|
(
|
||||||
|
tag("|"),
|
||||||
|
multispace0,
|
||||||
|
),
|
||||||
|
|i| term_precedence_4(i, d),
|
||||||
|
preceded
|
||||||
|
(
|
||||||
|
multispace0,
|
||||||
|
tag("|"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|argument| crate::Term::absolute_value(Box::new(argument)),
|
||||||
|
),
|
||||||
|
|i| term_precedence_4(i, d),
|
||||||
|
))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn term<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term>
|
||||||
|
{
|
||||||
|
term_precedence_5(i, d)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests
|
mod tests
|
||||||
{
|
{
|
||||||
use crate::parse::*;
|
use crate::parse::*;
|
||||||
use crate::Term;
|
use crate::{Term, VariableDeclaration, VariableDeclarationStack};
|
||||||
|
|
||||||
|
/*#[test]
|
||||||
|
fn parse_binary_operator()
|
||||||
|
{
|
||||||
|
assert!(binary_operator("+") == Ok(("", BinaryOperator::Add)));
|
||||||
|
assert!(binary_operator("+ ") == Ok((" ", BinaryOperator::Add)));
|
||||||
|
assert!(binary_operator("+3") == Ok(("3", BinaryOperator::Add)));
|
||||||
|
assert!(binary_operator("+ 3") == Ok((" 3", BinaryOperator::Add)));
|
||||||
|
assert!(binary_operator("+(rest") == Ok(("(rest", BinaryOperator::Add)));
|
||||||
|
assert!(binary_operator("+ (rest") == Ok((" (rest", BinaryOperator::Add)));
|
||||||
|
assert!(binary_operator("-") == Ok(("", BinaryOperator::Subtract)));
|
||||||
|
assert!(binary_operator("- ") == Ok((" ", BinaryOperator::Subtract)));
|
||||||
|
assert!(binary_operator("-3") == Ok(("3", BinaryOperator::Subtract)));
|
||||||
|
assert!(binary_operator("- 3") == Ok((" 3", BinaryOperator::Subtract)));
|
||||||
|
assert!(binary_operator("-(rest") == Ok(("(rest", BinaryOperator::Subtract)));
|
||||||
|
assert!(binary_operator("- (rest") == Ok((" (rest", BinaryOperator::Subtract)));
|
||||||
|
assert!(binary_operator("*") == Ok(("", BinaryOperator::Multiply)));
|
||||||
|
assert!(binary_operator("* ") == Ok((" ", BinaryOperator::Multiply)));
|
||||||
|
assert!(binary_operator("*3") == Ok(("3", BinaryOperator::Multiply)));
|
||||||
|
assert!(binary_operator("* 3") == Ok((" 3", BinaryOperator::Multiply)));
|
||||||
|
assert!(binary_operator("*(rest") == Ok(("(rest", BinaryOperator::Multiply)));
|
||||||
|
assert!(binary_operator("* (rest") == Ok((" (rest", BinaryOperator::Multiply)));
|
||||||
|
assert!(binary_operator("/") == Ok(("", BinaryOperator::Divide)));
|
||||||
|
assert!(binary_operator("/ ") == Ok((" ", BinaryOperator::Divide)));
|
||||||
|
assert!(binary_operator("/3") == Ok(("3", BinaryOperator::Divide)));
|
||||||
|
assert!(binary_operator("/ 3") == Ok((" 3", BinaryOperator::Divide)));
|
||||||
|
assert!(binary_operator("/(rest") == Ok(("(rest", BinaryOperator::Divide)));
|
||||||
|
assert!(binary_operator("/ (rest") == Ok((" (rest", BinaryOperator::Divide)));
|
||||||
|
assert!(binary_operator("%") == Ok(("", BinaryOperator::Modulo)));
|
||||||
|
assert!(binary_operator("% ") == Ok((" ", BinaryOperator::Modulo)));
|
||||||
|
assert!(binary_operator("%3") == Ok(("3", BinaryOperator::Modulo)));
|
||||||
|
assert!(binary_operator("% 3") == Ok((" 3", BinaryOperator::Modulo)));
|
||||||
|
assert!(binary_operator("%(rest") == Ok(("(rest", BinaryOperator::Modulo)));
|
||||||
|
assert!(binary_operator("% (rest") == Ok((" (rest", BinaryOperator::Modulo)));
|
||||||
|
assert!(binary_operator("**") == Ok(("", BinaryOperator::Exponentiate)));
|
||||||
|
assert!(binary_operator("** ") == Ok((" ", BinaryOperator::Exponentiate)));
|
||||||
|
assert!(binary_operator("**3") == Ok(("3", BinaryOperator::Exponentiate)));
|
||||||
|
assert!(binary_operator("** 3") == Ok((" 3", BinaryOperator::Exponentiate)));
|
||||||
|
assert!(binary_operator("**(rest") == Ok(("(rest", BinaryOperator::Exponentiate)));
|
||||||
|
assert!(binary_operator("** (rest") == Ok((" (rest", BinaryOperator::Exponentiate)));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*#[test]
|
||||||
|
fn parse_binary_operation()
|
||||||
|
{
|
||||||
|
assert_eq!(binary_operation("4 + 5", Declarations::new()),
|
||||||
|
Ok(("", Term::add(Box::new(Term::integer(4)), Box::new(Term::integer(5))))));
|
||||||
|
assert_eq!(binary_operation("4 + 5 + 7", Declarations::new()),
|
||||||
|
Ok(("", Term::add(Box::new(Term::integer(4)), Box::new(Term::integer(5))))));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_term_precedence_2()
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
crate::parse::terms::term_precedence_2("1 ** 2 ** 3 ** 4 ** 5", &Declarations::new()),
|
||||||
|
Ok(("", Term::exponentiate(Box::new(Term::integer(1)),
|
||||||
|
Box::new(Term::exponentiate(Box::new(Term::integer(2)),
|
||||||
|
Box::new(Term::exponentiate(Box::new(Term::integer(3)),
|
||||||
|
Box::new(Term::exponentiate(Box::new(Term::integer(4)),
|
||||||
|
Box::new(Term::integer(5))))))))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_term_precedence_3()
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
crate::parse::terms::term_precedence_3("1 * 2 / 3 % 4 * 5", &Declarations::new()),
|
||||||
|
Ok(("", Term::multiply(
|
||||||
|
Box::new(Term::modulo(
|
||||||
|
Box::new(Term::divide(
|
||||||
|
Box::new(Term::multiply(
|
||||||
|
Box::new(Term::integer(1)),
|
||||||
|
Box::new(Term::integer(2)))),
|
||||||
|
Box::new(Term::integer(3)))),
|
||||||
|
Box::new(Term::integer(4)))),
|
||||||
|
Box::new(Term::integer(5))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_term_precedence_4()
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
crate::parse::terms::term_precedence_4("1 + 2 - 3 + 4 - 5", &Declarations::new()),
|
||||||
|
Ok(("", Term::subtract(
|
||||||
|
Box::new(Term::add(
|
||||||
|
Box::new(Term::subtract(
|
||||||
|
Box::new(Term::add(
|
||||||
|
Box::new(Term::integer(1)),
|
||||||
|
Box::new(Term::integer(2)))),
|
||||||
|
Box::new(Term::integer(3)))),
|
||||||
|
Box::new(Term::integer(4)))),
|
||||||
|
Box::new(Term::integer(5))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_term_precedence_5()
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
crate::parse::terms::term_precedence_5("|1 + 2|", &Declarations::new()),
|
||||||
|
Ok(("", Term::absolute_value(
|
||||||
|
Box::new(Term::add(
|
||||||
|
Box::new(Term::integer(1)),
|
||||||
|
Box::new(Term::integer(2))))))));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_boolean()
|
fn parse_boolean()
|
||||||
@ -475,7 +789,7 @@ mod tests
|
|||||||
assert!(variable(" ", &Declarations::new()).is_err());
|
assert!(variable(" ", &Declarations::new()).is_err());
|
||||||
|
|
||||||
let new_variable_declarations = |names: &[&str]| std::rc::Rc::new(names.iter()
|
let new_variable_declarations = |names: &[&str]| std::rc::Rc::new(names.iter()
|
||||||
.map(|name| std::rc::Rc::new(crate::VariableDeclaration::new(name.to_string())))
|
.map(|name| std::rc::Rc::new(VariableDeclaration::new(name.to_string())))
|
||||||
.collect());
|
.collect());
|
||||||
|
|
||||||
let layer_1 = new_variable_declarations(&["A", "B", "X"]);
|
let layer_1 = new_variable_declarations(&["A", "B", "X"]);
|
||||||
@ -483,7 +797,7 @@ mod tests
|
|||||||
let layer_3 = new_variable_declarations(&["E", "F", "Y"]);
|
let layer_3 = new_variable_declarations(&["E", "F", "Y"]);
|
||||||
let layer_4 = new_variable_declarations(&["G", "H", "X"]);
|
let layer_4 = new_variable_declarations(&["G", "H", "X"]);
|
||||||
|
|
||||||
let variable_declaration_stack = crate::VariableDeclarationStack::new();
|
let variable_declaration_stack = VariableDeclarationStack::new();
|
||||||
|
|
||||||
let mut declarations = Declarations::new();
|
let mut declarations = Declarations::new();
|
||||||
declarations.variable_declaration_stack =
|
declarations.variable_declaration_stack =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user