grammar;
use aleph_syntax_tree::syntax::AlephTree as at;
// --- Program ---
// A PL/I program consists of a list of declarations and statements.
pub Program: at = {
<stmts:StatementList> => at::Module {
name: "PLI_PROGRAM".to_string(),
module_type: "program".to_string(),
id: None,
declarations: Vec::new(),
body: Some(stmts),
initialization: None,
}
}
// --- Statement List ---
// A list of statements (can be empty).
pub StatementList: Vec<Box<at>> = {
=> Vec::new(),
<stmts:NonEmptyStatementList> => stmts,
}
// --- Non-Empty Statement List ---
// A non-empty list of statements.
pub NonEmptyStatementList: Vec<Box<at>> = {
<stmt:Statement> => vec![Box::new(stmt)],
<stmts:NonEmptyStatementList> <stmt:Statement> => {
let mut v = stmts;
v.push(Box::new(stmt));
v
}
}
// --- Statement ---
// A single statement (assignment, procedure call, etc.).
pub Statement: at = {
<stmt:Assignment> => stmt,
<stmt:Call> => stmt,
<stmt:IfStmt> => stmt,
<stmt:Loop> => stmt,
<stmt:DeclareStmt> => stmt,
}
// --- Declare Statement ---
// A declare statement: "DECLARE Name TYPE [INIT(InitialValue)];"
pub DeclareStmt: at = {
"DECLARE" <name:Ident> <typ:Type> ";" => at::VarDecl {
name: name,
var_type: Some(Box::new(typ)),
initial_value: None,
is_constant: false,
is_aliased: false,
storage: None,
occurs: None,
usage: None,
attributes: Vec::new(),
level: None,
},
"DECLARE" <name:Ident> <typ:Type> "INIT" "(" <init:Expr> ")" ";" => at::VarDecl {
name: name,
var_type: Some(Box::new(typ)),
initial_value: Some(Box::new(init)),
is_constant: false,
is_aliased: false,
storage: None,
occurs: None,
usage: None,
attributes: Vec::new(),
level: None,
}
}
// --- Type ---
// A type: "FIXED", "FLOAT", "CHAR", etc.
pub Type: at = {
"FIXED" => at::TypeRef {
name: "FIXED".to_string(),
qualifiers: Vec::new(),
},
"FLOAT" => at::TypeRef {
name: "FLOAT".to_string(),
qualifiers: Vec::new(),
},
"CHAR" => at::TypeRef {
name: "CHAR".to_string(),
qualifiers: Vec::new(),
},
"BINARY" => at::TypeRef {
name: "BINARY".to_string(),
qualifiers: Vec::new(),
}
}
// --- Assignment ---
// An assignment statement: "Target = Expression;"
pub Assignment: at = {
<target:Ident> "=" <expr:Expr> ";" => at::Assignment {
target: Box::new(at::Ident { value: target }),
value: Box::new(expr),
}
}
// --- Procedure Call ---
// A procedure call: "CALL Name [Parameters];"
pub Call: at = {
"CALL" <name:Ident> ";" => at::Call {
target: Box::new(at::Ident { value: name }),
parameters: None,
returning: None,
on_error: None,
},
"CALL" <name:Ident> "(" <params:ParameterList> ")" ";" => at::Call {
target: Box::new(at::Ident { value: name }),
parameters: Some(params),
returning: None,
on_error: None,
}
}
// --- Parameter List ---
// A list of parameters (can be empty).
pub ParameterList: Vec<Box<at>> = {
=> Vec::new(),
<params:NonEmptyParameterList> => params,
}
// --- Non-Empty Parameter List ---
// A non-empty list of parameters.
pub NonEmptyParameterList: Vec<Box<at>> = {
<param:Parameter> => vec![Box::new(param)],
<params:NonEmptyParameterList> "," <param:Parameter> => {
let mut v = params;
v.push(Box::new(param));
v
}
}
// --- Parameter ---
// A single parameter: "Expression"
pub Parameter: at = {
<expr:Expr> => expr,
}
// --- If Statement ---
// An if statement: "IF Condition THEN [Statements] [ELSE [Statements]];"
pub IfStmt: at = {
"IF" <cond:Condition> "THEN" <then:StatementList> ";" => at::If {
condition: Box::new(cond),
then: Box::new(at::Block { statements: then }),
els: Box::new(at::Unit),
},
"IF" <cond:Condition> "THEN" <then:StatementList> "ELSE" <els:StatementList> ";" => at::If {
condition: Box::new(cond),
then: Box::new(at::Block { statements: then }),
els: Box::new(at::Block { statements: els }),
}
}
// --- Loop Statement ---
// A loop statement: "DO [Statements] END;"
pub Loop: at = {
"DO" <body:StatementList> "END" ";" => at::Loop {
name: None,
body: body,
}
}
// --- Condition ---
// A condition: "Expression"
pub Condition: at = {
<expr:Expr> => expr,
}
// --- Expression ---
// An expression (literal, identifier, operation, etc.).
pub Expr: at = {
<expr:AddExpr> => expr,
}
// --- AddExpr ---
// Addition and subtraction expressions.
pub AddExpr: at = {
<expr:MulExpr> => expr,
<left:AddExpr> "+" <right:MulExpr> => at::Add {
number_expr1: Box::new(left),
number_expr2: Box::new(right),
},
<left:AddExpr> "-" <right:MulExpr> => at::Sub {
number_expr1: Box::new(left),
number_expr2: Box::new(right),
},
}
// --- MulExpr ---
// Multiplication and division expressions.
pub MulExpr: at = {
<expr:EqExpr> => expr,
<left:MulExpr> "*" <right:EqExpr> => at::Mul {
number_expr1: Box::new(left),
number_expr2: Box::new(right),
},
<left:MulExpr> "/" <right:EqExpr> => at::Div {
number_expr1: Box::new(left),
number_expr2: Box::new(right),
},
}
// --- EqExpr ---
// Equality expressions.
pub EqExpr: at = {
<expr:PrimaryExpr> => expr,
<left:EqExpr> "=" <right:PrimaryExpr> => at::Eq {
expr1: Box::new(left),
expr2: Box::new(right),
},
<left:EqExpr> "<>" <right:PrimaryExpr> => at::NotEq {
expr1: Box::new(left),
expr2: Box::new(right),
},
}
// --- PrimaryExpr ---
// Primary expressions (literals, identifiers, parentheses).
pub PrimaryExpr: at = {
<lit:Literal> => lit,
<id:Ident> => at::Ident { value: id },
"(" <expr:Expr> ")" => expr,
}
// --- Literal ---
// A literal value (integer, string, etc.).
pub Literal: at = {
<lit:Int> => at::Int { value: lit },
<lit:String> => at::String { value: lit },
<lit:Bool> => at::Bool { value: lit },
}
// --- Integer ---
// An integer literal.
pub Int: String = {
r"-?[0-9]+" => <>.to_string(),
};
// --- String ---
// A string literal.
pub String: String = {
r#"'[^']*'"# => <>.to_string().trim_matches('\'').to_string(),
};
// --- Boolean ---
// A boolean literal.
pub Bool: String = {
"'1'B" => "true".to_string(),
"'0'B" => "false".to_string(),
"TRUE" => "true".to_string(),
"FALSE" => "false".to_string(),
};
// --- Identifier ---
// An identifier.
pub Ident: String = {
r#"[A-Za-z_][A-Za-z0-9_]*"# => <>.to_string(),
};